From b8b2c913f18bebe4f014e68a6eb298736c90468b Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 26 Apr 2021 19:05:31 +0200 Subject: [PATCH 001/551] Improve description of device handling, add `array.to_device` Closes gh-157 --- spec/API_specification/array_object.md | 21 +++++++++++++++++++++ spec/design_topics/device_support.md | 9 ++++++--- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index c5ea23491..ba1197692 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -1138,3 +1138,24 @@ Evaluates `self_i ^ other_i` for each element of an array instance with the resp Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_xor(x1, x2)`](elementwise_functions.md#bitwise_xorx1-x2-). ``` + +(method-to_device)= +### to\_device(self, device, /) + +Move the array to the given device. + +#### Parameters + +- **self**: _<array>_ + + - array instance. + +- **device**: _<device>_ + + - a `device` object (see {ref}`device-support`). + +#### Returns + +- **out**: _<array>_ + + - an array with the same data and dtype, located on the specified device. diff --git a/spec/design_topics/device_support.md b/spec/design_topics/device_support.md index 7788e2949..033e0b3a1 100644 --- a/spec/design_topics/device_support.md +++ b/spec/design_topics/device_support.md @@ -4,12 +4,15 @@ For libraries that support execution on more than a single hardware device - e.g. CPU and GPU, or multiple GPUs - it is important to be able to control on which device newly created arrays get placed and where execution happens. Attempting to be fully implicit doesn't always scale well to situations with multiple GPUs. -Existing libraries employ one or more of these three methods to exert such control: +Existing libraries employ one or more of these three methods to exert such control over data placement: + 1. A global default device, which may be fixed or user-switchable. 2. A context manager to control device assignment within its scope. -3. Local control via explicit keywords and a method to transfer arrays to another device. +3. Local control for data allocation target device via explicit keywords, and a method to transfer arrays to another device. + +Libraries differ in how execution is controlled, via a context manager or with the convention that execution takes place on the same device where all argument arrays are allocated. And they may or may not allow mixing arrays on different devices via implicit data transfers. -This standard chooses to add support for method 3 (local control), because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see {ref}`device-out-of-scope` for details. +This standard chooses to add support for method 3 (local control), with the convention that execution takes place on the same device where all argument arrays are allocated. The rationale for choosing method 3 is because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see {ref}`device-out-of-scope` for details. ## Intended usage From 2f2f290c4494b3632494175dc4c785c55b8682b7 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Fri, 4 Jun 2021 00:54:00 -0500 Subject: [PATCH 002/551] Add all fft functions --- .../fast_fourier_transform_functions.md | 670 ++++++++++++++++++ spec/extensions/index.rst | 1 + 2 files changed, 671 insertions(+) create mode 100644 spec/extensions/fast_fourier_transform_functions.md diff --git a/spec/extensions/fast_fourier_transform_functions.md b/spec/extensions/fast_fourier_transform_functions.md new file mode 100644 index 000000000..3bac54db6 --- /dev/null +++ b/spec/extensions/fast_fourier_transform_functions.md @@ -0,0 +1,670 @@ +# Fast Fourier Transform Functions + +> Array API specification for fast fourier transform functions. + +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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. + +## Objects in API + + +(function-fft)= +### fft(a, /, *, n=None, axis=-1, norm='backward') + +Computes the one-dimensional discrete Fourier Transform. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **n**: _int_ + + - Length of the transformed axis of the output. If it is `None`, the length of the input along the axis given by the `axis` keyword. Default: `None`. + +- **axis**: _int_ + + - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axis indicated by the `axis` keyword. + +#### Raises + +- If `axis` is larger than the last axis of `a`. + +(function-fft2)= +### fft2(a, /, *, s=None, axes=(-2, -1), norm='backward') + +Computes the two-dimensional discrete Fourier Transform. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If `axes` is not given and the length of `s` is different from 2. +- If an element of `axes` is larger than the number of axes of `a`. + +(function-fftfreq)= +### fftfreq(n, /, *, d=1.0) + +Returns the discrete Fourier Transform sample frequencies. For a Fourier Transform of length `n` and length unit of `d` the frequencies are described as: + +``` +f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even +f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd +``` + +#### Parameters + +- **n**: _int_ + + - Window length. + +- **d**: _float_ + + - Sample spacing between individual samples of the FFT input. Default: `1.0`. + +#### Returns + +- **out**: _<array>_ + + - An array of length `n` containing the sample frequencies. + +(function-fftn)= +### fftn(a, /, *, s=None, axes=None, norm='backward') + +Computes the n-dimensional discrete Fourier Transform. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If an element of `axes` is larger than the number of axes of `a`. + +(function-fftshift)= +### fftshift(x, /, *, axes=None) + +Reorders n-dimensional FTT data to have negative frequency terms first. In this way, the zero-frequency component shifts to the center of the spectrum. Note that `out[0]` is the Nyquist component only if the length of the input is even. + +#### Parameters + +- **x**: _<array>_ + + - Input array. + +- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to shift. If not specified, it shifts all axes. Default: `None`. + +#### Returns + +- **out**: _<array>_ + + - The shifted array. + +(function-hfft)= +### hfft(a, /, *, n=None, axis=-1, norm='backward') + +Computes the one-dimensional discrete Fourier Transform of a signal with Hermitian symmetry. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **n**: _int_ + + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + +- **axis**: _int_ + + - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - A transformed array. + +#### Raises + +- If `axis` is larger than the last axis of `a`. + +(function-ifft)= +### ifft(a, /, *, n=None, axis=-1, norm='backward') + +Computes the one-dimensional inverse discrete Fourier Transform. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **n**: _int_ + + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the IFFT. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. + +- **axis**: _int_ + + - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axis indicated by the `axis` keyword. + +#### Raises + +- If `axis` is larger than the last axis of `a`. + +(function-ifft2)= +### ifft2(a, /, *, s=None, axes=(-2, -1), norm='backward') + +Computes the two-dimensional inverse discrete Fourier Transform. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the inverse fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If `axes` is not given and the length of `s` is different from 2. +- If an element of `axes` is larger than the number of axes of `a`. + +(function-ifftn)= +### ifftn(a, /, *, s=None, axes=None, norm='backward') + +Computes the n-dimensional inverse discrete Fourier Transform. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the inverse fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If an element of `axes` is larger than the number of axes of `a`. + +(function-ifftshift)= +### ifftshift(x, /, *, axes=None) + +Inverse of `fftshift`. + +#### Parameters + +- **x**: _<array>_ + + - Input array. + +- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to calculate. If not specified, it shifts all axes. Default: `None`. + +#### Returns + +- **out**: _<array>_ + + - The shifted array. + +(function-ihfft)= +### ihfft(a, /, *, n=None, axis=-1, norm='backward') + +Computes the one-dimensional inverse discrete Fourier Transform of a signal with Hermitian symmetry. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **n**: _int_ + + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + +- **axis**: _int_ + + - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - A transformed array. + +#### Raises + +- If `axis` is larger than the last axis of `a`. + +(function-irfft)= +### irfft(a, /, *, n=None, axis=-1, norm='backward') + +Computes the one-dimensional inverse discrete Fourier Transform for real-valued input. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **n**: _int_ + + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + +- **axis**: _int_ + + - Axis used to compute the real fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axis indicated by the `axis` keyword. + +#### Raises + +- If `axis` is larger than the last axis of `a`. + +(function-irfft2)= +### irfft2(a, /, *, s=None, axes=(-2, -1), norm='backward') + +Computes the two-dimensional inverse discrete Fourier Transform for real-valued input. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axes` keyword. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes used to compute the real fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If `axes` is not given and the length of `s` is different from 2. +- If an element of `axes` is larger than the number of axes of `a`. + +(function-irfftn)= +### irfftn(a, /, *, s=None, axes=None, norm='backward') + +Computes the n-dimensional inverse discrete Fourier Transform for real-valued input. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the inverse fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If an element of `axes` is larger than the number of axes of `a`. + + +(function-rfft)= +### rfft(a, /, *, n=None, axis=-1, norm='backward') + +Computes the one-dimensional discrete Fourier Transform for real-valued input. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **n**: _int_ + + - Length of the input array. If given, the input will be either zero-padded or trimmed to this length before computing the real FFT. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. + +- **axis**: _int_ + + - Axis used to compute the real fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axis indicated by the `axis` keyword. + +#### Raises + +- If `axis` is larger than the last axis of `a`. + +(function-rfft2)= +### rfft2(a, /, *, s=None, axes=(-2, -1), norm='backward') + +Computes the two-dimensional discrete Fourier Transform for real-valued input. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If `axes` is not given and the length of `s` is different from 2. +- If an element of `axes` is larger than the number of axes of `a`. + +(function-rfftfreq)= +### rfftfreq(n, /, *, d=1.0) + +Returns the discrete Fourier Transform sample frequencies. For a Fourier Transform of length `n` and length unit of `d` the frequencies are described as: + +``` +f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even +f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd +``` + +The Nyquist frequency component is considered to be positive. + +#### Parameters + +- **n**: _int_ + + - Window length. + +- **d**: _float_ + + - Sample spacing between individual samples of the FFT input. Default: `1.0`. + +#### Returns + +- **out**: _<array>_ + + - An array of length `n` containing the sample frequencies. + +(function-rfftn)= +### rfftn(a, /, *, s=None, axes=None, norm='backward') + +Computes the n-dimensional discrete Fourier Transform for real-valued input. + +#### Parameters + +- **a**: _<array>_ + + - Input array. + +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the real fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: No normalization. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: Normalize by `1/n`. + + Default: `'backward'` + +#### Returns + +- **out**: _<array>_ + + - An array transformed along the axes indicated by the `axes` keyword. + +#### Raises + +- If `s` and `axes` have a different length. +- If an element of `axes` is larger than the number of axes of `a`. \ No newline at end of file diff --git a/spec/extensions/index.rst b/spec/extensions/index.rst index 1b3b7470f..23bdd727b 100644 --- a/spec/extensions/index.rst +++ b/spec/extensions/index.rst @@ -7,4 +7,5 @@ Extensions :caption: Extensions :maxdepth: 3 + fast_fourier_transform_functions linear_algebra_functions From 63c592eadb63e2ca42f842fdd51f786ef1a1ff06 Mon Sep 17 00:00:00 2001 From: Tom White Date: Fri, 4 Jun 2021 18:59:36 +0100 Subject: [PATCH 003/551] Fix typo in definition of __lshift__ (#190) --- spec/API_specification/array_object.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 0f2c3deca..fb711feda 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -737,7 +737,7 @@ Evaluates `self_i << other_i` for each element of an array instance with the res ```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`less_equal(x1, x2)`](elementwise_functions.md#bitwise_left_shiftx1-x2-). +Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_left_shift(x1, x2)`](elementwise_functions.md#bitwise_left_shiftx1-x2-). ``` (method-__lt__)= From 287e6869a2ba6b08290966c41b77698b7e6e6ca0 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 8 Jun 2021 14:22:07 -0500 Subject: [PATCH 004/551] add consistency among the definitions and add some minor fixes --- ...ions.md => fourier_transform_functions.md} | 122 +++++++++--------- spec/extensions/index.rst | 2 +- 2 files changed, 62 insertions(+), 62 deletions(-) rename spec/extensions/{fast_fourier_transform_functions.md => fourier_transform_functions.md} (72%) diff --git a/spec/extensions/fast_fourier_transform_functions.md b/spec/extensions/fourier_transform_functions.md similarity index 72% rename from spec/extensions/fast_fourier_transform_functions.md rename to spec/extensions/fourier_transform_functions.md index 3bac54db6..8dfcf2b5b 100644 --- a/spec/extensions/fast_fourier_transform_functions.md +++ b/spec/extensions/fourier_transform_functions.md @@ -1,6 +1,6 @@ -# Fast Fourier Transform Functions +# Fourier transform Functions -> Array API specification for fast fourier transform functions. +> Array API specification for Fourier transform functions. A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. @@ -17,7 +17,7 @@ A conforming implementation of the array API standard must provide and support t (function-fft)= ### fft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional discrete Fourier Transform. +Computes the one-dimensional discrete Fourier transform. #### Parameters @@ -31,7 +31,7 @@ Computes the one-dimensional discrete Fourier Transform. - **axis**: _int_ - - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ @@ -56,7 +56,7 @@ Computes the one-dimensional discrete Fourier Transform. (function-fft2)= ### fft2(a, /, *, s=None, axes=(-2, -1), norm='backward') -Computes the two-dimensional discrete Fourier Transform. +Computes the two-dimensional discrete Fourier transform. #### Parameters @@ -66,11 +66,11 @@ Computes the two-dimensional discrete Fourier Transform. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + - Axes over which to compute the Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - **norm**: _str_ @@ -97,7 +97,7 @@ Computes the two-dimensional discrete Fourier Transform. (function-fftfreq)= ### fftfreq(n, /, *, d=1.0) -Returns the discrete Fourier Transform sample frequencies. For a Fourier Transform of length `n` and length unit of `d` the frequencies are described as: +Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length `n` and length unit of `d` the frequencies are described as: ``` f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even @@ -112,7 +112,7 @@ f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd - **d**: _float_ - - Sample spacing between individual samples of the FFT input. Default: `1.0`. + - Sample spacing between individual samples of the Fourier transform input. Default: `1.0`. #### Returns @@ -123,7 +123,7 @@ f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd (function-fftn)= ### fftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional discrete Fourier Transform. +Computes the n-dimensional discrete Fourier transform. #### Parameters @@ -133,11 +133,11 @@ Computes the n-dimensional discrete Fourier Transform. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + - Axes over which to compute the Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. - **norm**: _str_ @@ -184,7 +184,7 @@ Reorders n-dimensional FTT data to have negative frequency terms first. In this (function-hfft)= ### hfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional discrete Fourier Transform of a signal with Hermitian symmetry. +Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. #### Parameters @@ -194,11 +194,11 @@ Computes the one-dimensional discrete Fourier Transform of a signal with Hermiti - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ - - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ @@ -223,7 +223,7 @@ Computes the one-dimensional discrete Fourier Transform of a signal with Hermiti (function-ifft)= ### ifft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional inverse discrete Fourier Transform. +Computes the one-dimensional inverse discrete Fourier transform. #### Parameters @@ -233,19 +233,19 @@ Computes the one-dimensional inverse discrete Fourier Transform. - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the IFFT. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the IFourier transform. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ - - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: No normalization. + - `'backward'`: Normalize by `1/n`. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. + - `'forward'`: No normalization. Default: `'backward'` @@ -262,7 +262,7 @@ Computes the one-dimensional inverse discrete Fourier Transform. (function-ifft2)= ### ifft2(a, /, *, s=None, axes=(-2, -1), norm='backward') -Computes the two-dimensional inverse discrete Fourier Transform. +Computes the two-dimensional inverse discrete Fourier transform. #### Parameters @@ -272,19 +272,19 @@ Computes the two-dimensional inverse discrete Fourier Transform. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the inverse fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + - Axes over which to compute the inverse Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: No normalization. + - `'backward'`: Normalize by `1/n`. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. + - `'forward'`: No normalization. Default: `'backward'` @@ -303,7 +303,7 @@ Computes the two-dimensional inverse discrete Fourier Transform. (function-ifftn)= ### ifftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional inverse discrete Fourier Transform. +Computes the n-dimensional inverse discrete Fourier transform. #### Parameters @@ -313,19 +313,19 @@ Computes the n-dimensional inverse discrete Fourier Transform. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the inverse fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + - Axes over which to compute the inverse Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: No normalization. + - `'backward'`: Normalize by `1/n`. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. + - `'forward'`: No normalization. Default: `'backward'` @@ -364,7 +364,7 @@ Inverse of `fftshift`. (function-ihfft)= ### ihfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional inverse discrete Fourier Transform of a signal with Hermitian symmetry. +Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. #### Parameters @@ -374,19 +374,19 @@ Computes the one-dimensional inverse discrete Fourier Transform of a signal with - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ - - Axis used to compute the fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: No normalization. + - `'backward'`: Normalize by `1/n`. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. + - `'forward'`: No normalization. Default: `'backward'` @@ -403,7 +403,7 @@ Computes the one-dimensional inverse discrete Fourier Transform of a signal with (function-irfft)= ### irfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional inverse discrete Fourier Transform for real-valued input. +Computes the one-dimensional inverse discrete Fourier transform for real-valued input. #### Parameters @@ -413,19 +413,19 @@ Computes the one-dimensional inverse discrete Fourier Transform for real-valued - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ - - Axis used to compute the real fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: No normalization. + - `'backward'`: Normalize by `1/n`. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. + - `'forward'`: No normalization. Default: `'backward'` @@ -442,7 +442,7 @@ Computes the one-dimensional inverse discrete Fourier Transform for real-valued (function-irfft2)= ### irfft2(a, /, *, s=None, axes=(-2, -1), norm='backward') -Computes the two-dimensional inverse discrete Fourier Transform for real-valued input. +Computes the two-dimensional inverse discrete Fourier transform for real-valued input. #### Parameters @@ -452,19 +452,19 @@ Computes the two-dimensional inverse discrete Fourier Transform for real-valued - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real FFT. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axes` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axes` keyword. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes used to compute the real fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + - Axes used to compute the real Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: No normalization. + - `'backward'`: Normalize by `1/n`. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. + - `'forward'`: No normalization. Default: `'backward'` @@ -483,7 +483,7 @@ Computes the two-dimensional inverse discrete Fourier Transform for real-valued (function-irfftn)= ### irfftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional inverse discrete Fourier Transform for real-valued input. +Computes the n-dimensional inverse discrete Fourier transform for real-valued input. #### Parameters @@ -493,19 +493,19 @@ Computes the n-dimensional inverse discrete Fourier Transform for real-valued in - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the inverse fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + - Axes over which to compute the inverse Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: No normalization. + - `'backward'`: Normalize by `1/n`. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. + - `'forward'`: No normalization. Default: `'backward'` @@ -524,7 +524,7 @@ Computes the n-dimensional inverse discrete Fourier Transform for real-valued in (function-rfft)= ### rfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional discrete Fourier Transform for real-valued input. +Computes the one-dimensional discrete Fourier transform for real-valued input. #### Parameters @@ -534,11 +534,11 @@ Computes the one-dimensional discrete Fourier Transform for real-valued input. - **n**: _int_ - - Length of the input array. If given, the input will be either zero-padded or trimmed to this length before computing the real FFT. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. + - Length of the input array. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. - **axis**: _int_ - - Axis used to compute the real fast fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ @@ -563,7 +563,7 @@ Computes the one-dimensional discrete Fourier Transform for real-valued input. (function-rfft2)= ### rfft2(a, /, *, s=None, axes=(-2, -1), norm='backward') -Computes the two-dimensional discrete Fourier Transform for real-valued input. +Computes the two-dimensional discrete Fourier transform for real-valued input. #### Parameters @@ -573,11 +573,11 @@ Computes the two-dimensional discrete Fourier Transform for real-valued input. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the fast fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. + - Axes over which to compute the Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - **norm**: _str_ @@ -604,7 +604,7 @@ Computes the two-dimensional discrete Fourier Transform for real-valued input. (function-rfftfreq)= ### rfftfreq(n, /, *, d=1.0) -Returns the discrete Fourier Transform sample frequencies. For a Fourier Transform of length `n` and length unit of `d` the frequencies are described as: +Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length `n` and length unit of `d` the frequencies are described as: ``` f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even @@ -621,7 +621,7 @@ The Nyquist frequency component is considered to be positive. - **d**: _float_ - - Sample spacing between individual samples of the FFT input. Default: `1.0`. + - Sample spacing between individual samples of the Fourier transform input. Default: `1.0`. #### Returns @@ -632,7 +632,7 @@ The Nyquist frequency component is considered to be positive. (function-rfftn)= ### rfftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional discrete Fourier Transform for real-valued input. +Computes the n-dimensional discrete Fourier transform for real-valued input. #### Parameters @@ -642,11 +642,11 @@ Computes the n-dimensional discrete Fourier Transform for real-valued input. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the real fast fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the real Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the fast fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + - Axes over which to compute the Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. - **norm**: _str_ diff --git a/spec/extensions/index.rst b/spec/extensions/index.rst index 23bdd727b..7fe36f3ad 100644 --- a/spec/extensions/index.rst +++ b/spec/extensions/index.rst @@ -7,5 +7,5 @@ Extensions :caption: Extensions :maxdepth: 3 - fast_fourier_transform_functions + fourier_transform_functions linear_algebra_functions From 64cad4b95cc2f60d89c82b88b3e3e91b90d4a4ae Mon Sep 17 00:00:00 2001 From: Anirudh Date: Thu, 10 Jun 2021 14:25:55 +0530 Subject: [PATCH 005/551] [Docs] Fix minor rendering bugs (#196) * [Docs] Fix indendation and rendering of Rationale * add link for gh-1 * [Docs] Fix rendering of interchange mechanisms --- spec/design_topics/data_interchange.md | 8 ++++++++ spec/purpose_and_scope.md | 8 ++++---- spec/use_cases.md | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/spec/design_topics/data_interchange.md b/spec/design_topics/data_interchange.md index a834db3ae..d01f5adad 100644 --- a/spec/design_topics/data_interchange.md +++ b/spec/design_topics/data_interchange.md @@ -12,20 +12,28 @@ The interchange mechanism must offer the following: 1. Data access via a protocol that describes the memory layout of the array in an implementation-independent manner. + _Rationale: any number of libraries must be able to exchange data, and no particular package must be needed to do so._ + 2. Support for all dtypes in this API standard (see {ref}`data-types`). + 3. Device support. It must be possible to determine on what device the array that is to be converted lives. + _Rationale: there are CPU-only, GPU-only, and multi-device array types; it's best to support these with a single protocol (with separate per-device protocols it's hard to figure out unambiguous rules for which protocol gets used, and the situation will get more complex over time as TPU's and other accelerators become more widely available)._ + 4. Zero-copy semantics where possible, making a copy only if needed (e.g. when data is not contiguous in memory). + _Rationale: performance._ + 5. A Python-side and a C-side interface, the latter with a stable C ABI. + _Rationale: all prominent existing array libraries are implemented in C/C++, and are released independently from each other. Hence a stable C ABI is required for packages to work well together._ diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index a8fb596c6..56046a277 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -187,10 +187,10 @@ extensions are dealt with_): 7. Behaviour for unexpected/invalid input to functions and methods. - _Rationale: there are a huge amount of ways in which users can provide - invalid or unspecified input to functionality in the standard. Exception - types or other resulting behaviour cannot be completely covered and would - be hard to make consistent between libraries._ + _Rationale: there are a huge amount of ways in which users can provide + invalid or unspecified input to functionality in the standard. Exception + types or other resulting behaviour cannot be completely covered and would + be hard to make consistent between libraries._ **Non-goals** for the API standard include: diff --git a/spec/use_cases.md b/spec/use_cases.md index bd9f4888e..50b6bd24d 100644 --- a/spec/use_cases.md +++ b/spec/use_cases.md @@ -50,7 +50,7 @@ parallelism in some algorithms. However SciPy itself will not directly start depending on a GPU or distributed array implementation, or contain (e.g.) CUDA code - that's not maintainable given the resources for development. _However_, there is a way to provide distributed or GPU support. Part of the -solution is provided by NumPy's "array protocols" (see gh-1), that allow +solution is provided by NumPy's "array protocols" (see [gh-1](https://github.com/data-apis/array-api/issues/1)), that allow dispatching to other array implementations. The main problem then becomes how to know whether this will work with a particular distributed or GPU array implementation - given that there are zero other array implementations that From 7038c9c2b4f1f6685a6ea5f727bd66be7fb999ac Mon Sep 17 00:00:00 2001 From: Kshiteej K Date: Fri, 11 Jun 2021 23:29:15 +0530 Subject: [PATCH 006/551] Fix rendering (#198) --- spec/API_specification/type_promotion.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/API_specification/type_promotion.md b/spec/API_specification/type_promotion.md index a0e66f18c..e2ec506e0 100644 --- a/spec/API_specification/type_promotion.md +++ b/spec/API_specification/type_promotion.md @@ -108,6 +108,7 @@ a compatible type and value to the array dtype: - Python `bool` for a `bool` array dtype, - a Python `int` within the [bounds](data-types) of the given dtype for integer array dtypes, - a Python `int` or `float` for floating-point array dtypes + The expected behavior is then equivalent to: 1. Convert the scalar to a 0-D array with the same dtype as that of the array From 94694876a2bce7d5b21f328a01bcad183fdf41c2 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 14 Jun 2021 12:39:01 -0700 Subject: [PATCH 007/551] Add clarification note regarding arithmetic shift (#200) --- spec/API_specification/elementwise_functions.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index aa69c9a6a..c19d658e6 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -397,6 +397,11 @@ Computes the bitwise OR of the underlying binary representation of each element Shifts the bits of each element `x1_i` of the input array `x1` to the right according to the respective element `x2_i` of the input array `x2`. +```{note} + +This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. +``` + #### Parameters - **x1**: _<array>_ From 777bece1fce6b2db0f92bd6cfabe61a93047c01c Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 14 Jun 2021 12:45:22 -0700 Subject: [PATCH 008/551] Update output dtypes for bitwise shift operations (#201) --- spec/API_specification/elementwise_functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index c19d658e6..01a7a35d9 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -352,7 +352,7 @@ Shifts the bits of each element `x1_i` of the input array `x1` to the left by ap - **out**: _<array>_ - - an array containing the element-wise results. The returned array must have the same data type as `x1`. + - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. (function-bitwise_invert)= ### bitwise_invert(x, /) @@ -416,7 +416,7 @@ This operation must be an arithmetic shift (i.e., sign-propagating) and thus equ - **out**: _<array>_ - - an array containing the element-wise results. The returned array must have the same data type as `x1`. + - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. (function-bitwise_xor)= ### bitwise_xor(x1, x2, /) From 8da3d42a26fd21f115748ef7c9c48f47a1b4079d Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 14 Jun 2021 14:46:54 -0500 Subject: [PATCH 009/551] PR: Add smallest normal to finfo class (#194) --- spec/API_specification/data_type_functions.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/API_specification/data_type_functions.md b/spec/API_specification/data_type_functions.md index 0b76b386b..5a8165411 100644 --- a/spec/API_specification/data_type_functions.md +++ b/spec/API_specification/data_type_functions.md @@ -95,6 +95,8 @@ Machine limits for floating-point data types. - largest representable number. - **min**: _float_ - smallest representable number. + - **smallest_normal**: _float_ + - smallest positive floating-point number with full precision. (function-iinfo)= ### iinfo(type, /) From 07d0654a339b5d5a660471b9d75e1dcf5ba960cd Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 24 Jun 2021 14:36:58 -0500 Subject: [PATCH 010/551] Remove *fft2 functions --- .../extensions/fourier_transform_functions.md | 164 ------------------ 1 file changed, 164 deletions(-) diff --git a/spec/extensions/fourier_transform_functions.md b/spec/extensions/fourier_transform_functions.md index 8dfcf2b5b..5153b354e 100644 --- a/spec/extensions/fourier_transform_functions.md +++ b/spec/extensions/fourier_transform_functions.md @@ -53,47 +53,6 @@ Computes the one-dimensional discrete Fourier transform. - If `axis` is larger than the last axis of `a`. -(function-fft2)= -### fft2(a, /, *, s=None, axes=(-2, -1), norm='backward') - -Computes the two-dimensional discrete Fourier transform. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to compute the Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - An array transformed along the axes indicated by the `axes` keyword. - -#### Raises - -- If `s` and `axes` have a different length. -- If `axes` is not given and the length of `s` is different from 2. -- If an element of `axes` is larger than the number of axes of `a`. - (function-fftfreq)= ### fftfreq(n, /, *, d=1.0) @@ -259,47 +218,6 @@ Computes the one-dimensional inverse discrete Fourier transform. - If `axis` is larger than the last axis of `a`. -(function-ifft2)= -### ifft2(a, /, *, s=None, axes=(-2, -1), norm='backward') - -Computes the two-dimensional inverse discrete Fourier transform. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to compute the inverse Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: Normalize by `1/n`. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - An array transformed along the axes indicated by the `axes` keyword. - -#### Raises - -- If `s` and `axes` have a different length. -- If `axes` is not given and the length of `s` is different from 2. -- If an element of `axes` is larger than the number of axes of `a`. - (function-ifftn)= ### ifftn(a, /, *, s=None, axes=None, norm='backward') @@ -439,47 +357,6 @@ Computes the one-dimensional inverse discrete Fourier transform for real-valued - If `axis` is larger than the last axis of `a`. -(function-irfft2)= -### irfft2(a, /, *, s=None, axes=(-2, -1), norm='backward') - -Computes the two-dimensional inverse discrete Fourier transform for real-valued input. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axes` keyword. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes used to compute the real Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: Normalize by `1/n`. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - An array transformed along the axes indicated by the `axes` keyword. - -#### Raises - -- If `s` and `axes` have a different length. -- If `axes` is not given and the length of `s` is different from 2. -- If an element of `axes` is larger than the number of axes of `a`. - (function-irfftn)= ### irfftn(a, /, *, s=None, axes=None, norm='backward') @@ -560,47 +437,6 @@ Computes the one-dimensional discrete Fourier transform for real-valued input. - If `axis` is larger than the last axis of `a`. -(function-rfft2)= -### rfft2(a, /, *, s=None, axes=(-2, -1), norm='backward') - -Computes the two-dimensional discrete Fourier transform for real-valued input. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to compute the Fourier transform. If it is not specified, the last two axes are used. Default: `(-2, -1)`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - An array transformed along the axes indicated by the `axes` keyword. - -#### Raises - -- If `s` and `axes` have a different length. -- If `axes` is not given and the length of `s` is different from 2. -- If an element of `axes` is larger than the number of axes of `a`. - (function-rfftfreq)= ### rfftfreq(n, /, *, d=1.0) From bf3ea77b4e46ec7d037a8a0c51c0f6ef75c12220 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 27 Jun 2021 14:23:03 -0700 Subject: [PATCH 011/551] Require output to be default integer dtype (#205) --- spec/API_specification/set_functions.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/spec/API_specification/set_functions.md b/spec/API_specification/set_functions.md index c8d04cffa..b39122f76 100644 --- a/spec/API_specification/set_functions.md +++ b/spec/API_specification/set_functions.md @@ -59,6 +59,4 @@ Returns the unique elements of an input array `x`. - **counts**: _<array>_ - - an array containing the number of times each unique element occurs in `x`. - - _TODO: should this be `int64`? This probably makes sense for most hardware; however, may be undesirable for older hardware and/or embedded systems._ + - an array containing the number of times each unique element occurs in `x`. The returned array must have the default integer data type. From 8dade11e5d79fae2741f766adc804a9808e2418c Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 27 Jun 2021 14:24:17 -0700 Subject: [PATCH 012/551] Update copy (#206) --- spec/API_specification/data_types.md | 40 +++++++++++++++++++--------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/spec/API_specification/data_types.md b/spec/API_specification/data_types.md index 3788d8494..37f528c7a 100644 --- a/spec/API_specification/data_types.md +++ b/spec/API_specification/data_types.md @@ -6,13 +6,6 @@ A conforming implementation of the array API standard must provide and support the following data types. -A conforming implementation of the array API standard must define a default floating-point data type (either `float32` or `float64`), as well as a default integer data type (`int32` or `int64`). These default data types must be the same across platforms. The default integer data type may vary depending on whether Python is 32-bit or 64-bit. - -```{note} -The default floating-point and array index integer data types should be clearly defined in a conforming library's documentation. -``` - - ## bool Boolean (`True` or `False`). @@ -60,8 +53,9 @@ IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-20 :::{admonition} Future extension :class: hint -It is expected that in the next version of this standard, `complex64` and `complex128` -dtypes will be added, with these casting rules (will be added to {ref}`type-promotion`): +`complex64` and `complex128` dtypes are expected to be included in the next +version of this standard and to have the following casting rules (will be added +to {ref}`type-promotion`): ![Type promotion diagram for complex dtypes in next version](/_static/images/dtype_promotion_complex.png) @@ -78,13 +72,33 @@ Implementations may provide other ways to specify data types (e.g., A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. ``` +(data-type-defaults)= +## Default Data Types + +A conforming implementation of the array API standard must define a default floating-point data type (either `float32` or `float64`) and a default integer data type (`int32` or `int64`). + +The default data types must be the same across platforms. + +The default integer data type may vary depending on whether Python is 32-bit or 64-bit. + +```{note} +The default floating-point and integer data types should be clearly defined in a conforming library's documentation. +``` + (data-type-categories)= ## Data Type Categories -For the purposes of this specification, the following data type categories are defined. -Libraries do not need to organize dtypes according to these categories. These -are only for organizing the functions in this specification itself. Future versions of -the specification will include additional categories for complex data types. +For the purpose of organizing functions within this specification, the following data type categories are defined. + +```{note} +Conforming libraries are not required to organize dtypes according to these categories. These +categories are only intended for use within this specification. +``` + +```{note} +Future versions of the specification will include additional categories for +complex data types. +``` ### Numeric Data Types From b7b0dcd93a4205f79cbf74746403737cc675274c Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 28 Jun 2021 13:42:02 -0700 Subject: [PATCH 013/551] Clarify guidance on operations having data-dependent output shapes (#193) * Add note for functions that doesn't support boolean array indexing * clarify the notes * remove note from where function * Create a unique admonition for data-dependent shapes * Rewrite note with the given suggestions * Update notes * Add document stub * Add admonition for boolean array indexing and update reference * Add explainer on data-dependent output shapes * Fix typo * Update copy Co-authored-by: Stephan Hoyer * Update copy Co-authored-by: Leo Fang * Update copy Co-authored-by: Stephannie Jimenez Co-authored-by: Ralf Gommers Co-authored-by: Stephan Hoyer Co-authored-by: Leo Fang --- spec/API_specification/indexing.md | 6 ++++++ spec/API_specification/searching_functions.md | 6 ++++++ spec/API_specification/set_functions.md | 6 ++++++ .../design_topics/data_dependent_output_shapes.md | 15 +++++++++++++++ spec/design_topics/index.rst | 1 + 5 files changed, 34 insertions(+) create mode 100644 spec/design_topics/data_dependent_output_shapes.md diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 57689d489..23998a8cf 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -160,6 +160,12 @@ _Rationale: this is consistent with bounds-checking for single-axis indexing. An ## Boolean Array Indexing +:::{admonition} Data-dependent output shape +:class: important + +For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See {ref}`data-dependent-output-shapes` section for more details. +::: + An array must support indexing where the **sole index** is an `M`-dimensional boolean array `B` with shape `S1 = (s1, ..., sM)` according to the following rules. Let `A` be an `N`-dimensional array with shape `S2 = (s1, ..., sM, ..., sN)`. - If `N >= M`, then `A[B]` must replace the first `M` dimensions of `A` with a single dimension having a size equal to the number of `True` elements in `B`. The values in the resulting array must be in row-major (C-style order); this is equivalent to `A[nonzero(B)]`. diff --git a/spec/API_specification/searching_functions.md b/spec/API_specification/searching_functions.md index d3d06d7a6..3ad2ae8bb 100644 --- a/spec/API_specification/searching_functions.md +++ b/spec/API_specification/searching_functions.md @@ -69,6 +69,12 @@ Returns the indices of the minimum values along a specified axis. When the minim (function-nonzero)= ### nonzero(x, /) +:::{admonition} Data-dependent output shape +:class: important + +The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. +::: + Returns the indices of the array elements which are non-zero. #### Parameters diff --git a/spec/API_specification/set_functions.md b/spec/API_specification/set_functions.md index b39122f76..e00b116f9 100644 --- a/spec/API_specification/set_functions.md +++ b/spec/API_specification/set_functions.md @@ -15,6 +15,12 @@ A conforming implementation of the array API standard must provide and support t (function-unique)= ### unique(x, /, *, return_counts=False, return_index=False, return_inverse=False) +:::{admonition} Data-dependent output shape +:class: important + +The shapes of one or more of output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. +::: + Returns the unique elements of an input array `x`. #### Parameters diff --git a/spec/design_topics/data_dependent_output_shapes.md b/spec/design_topics/data_dependent_output_shapes.md new file mode 100644 index 000000000..d8347520d --- /dev/null +++ b/spec/design_topics/data_dependent_output_shapes.md @@ -0,0 +1,15 @@ +(data-dependent-output-shapes)= + +# Data-dependent output shapes + +Array libraries which build computation graphs commonly employ static analysis that relies upon known shapes. For example, JAX requires known array sizes when compiling code, in order to perform static memory allocation. Functions and operations which are value-dependent present difficulties for such libraries, as array sizes cannot be inferred ahead of time without also knowing the contents of the respective arrays. + +While value-dependent functions and operations are not impossible to implement for array libraries which build computation graphs, this specification does not want to impose an undue burden on such libraries and permits omission of value-dependent operations. All other array libraries are expected, however, to implement the value-dependent operations included in this specification in order to be array specification compliant. + +Value-dependent operations are demarcated in this specification using an admonition similar to the following: + +:::{admonition} Data-dependent output shape +:class: important + +The shape of the output array for this function/operation depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function/operation difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. +::: diff --git a/spec/design_topics/index.rst b/spec/design_topics/index.rst index 6e41899ca..2729cdbe4 100644 --- a/spec/design_topics/index.rst +++ b/spec/design_topics/index.rst @@ -6,6 +6,7 @@ Design topics & constraints :maxdepth: 1 copies_views_and_mutation + data_dependent_output_shapes data_interchange device_support static_typing From dffc7ab79771de9672a2aa7a28db4502892f601d Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 28 Jun 2021 13:50:55 -0700 Subject: [PATCH 014/551] Clarify `eig` and `eigvals` TODOs (#204) --- spec/extensions/linear_algebra_functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 5f9eaf0a7..ab99301d9 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -177,7 +177,7 @@ Returns the specified diagonals. If `x` has more than two dimensions, then the a (function-linalg-eig)= ### linalg.eig() -TODO +_TODO: this requires complex number support to be added to the specification._ (function-linalg-eigh)= ### linalg.eigh(x, /, *, upper=False) @@ -215,7 +215,7 @@ Eigenvalue sort order is left unspecified. (function-linalg-eigvals)= ### linalg.eigvals() -TODO +_TODO: this requires complex number support to be added to the specification._ (function-linalg-eigvalsh)= ### linalg.eigvalsh(x, /, *, upper=False) From 8a1602e705610df8904ad99a010c26be2903fbe6 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 28 Jun 2021 13:52:29 -0700 Subject: [PATCH 015/551] Update guidance on tuple field names (#203) --- spec/extensions/linear_algebra_functions.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index ab99301d9..423e17b85 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -200,10 +200,10 @@ Returns the eigenvalues and eigenvectors of a symmetric matrix (or a stack of sy - **out**: _Tuple\[ <array> ]_ - - a namedtuple (`e`, `v`) whose + - a namedtuple (`eigenvalues`, `eigenvectors`) whose - - first element must have shape `(..., M)` and consist of computed eigenvalues. - - second element must have shape `(..., M, M)`and have the columns of the inner most matrices contain the computed eigenvectors. + - first element must have the field name `eigenvalues` and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape `(..., M)`. + - second element have have the field name `eigenvectors` and must be an array where the columns of the inner most matrices contain the computed eigenvectors. The array containing the eigenvectors must have shape `(..., M, M)`. Each returned array must have the same floating-point data type as `x`. @@ -493,8 +493,8 @@ Computes the qr factorization of a matrix (or a stack of matrices), where `q` is - a namedtuple `(q, r)` whose - - first element must be an array whose shape depends on the value of `mode` and contain orthonormal matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. - - second element must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. + - first element must have the field name `q` and must be an array whose shape depends on the value of `mode` and contain orthonormal matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. + - second element must have the field name `r` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. Each returned array must have a floating-point data type determined by {ref}`type-promotion`. @@ -520,8 +520,8 @@ The purpose of this function is to calculate the determinant more accurately whe - a namedtuple (`sign`, `logabsdet`) whose - - first element must be an array containing a number representing the sign of the determinant for each square matrix. - - second element must be an array containing the determinant for each square matrix. + - first element must have the field name `sign` and must be an array containing a number representing the sign of the determinant for each square matrix. + - second element must have the field name `logabsdet` and must be an array containing the determinant for each square matrix. For a real matrix, the sign of the determinant must be either `1`, `0`, or `-1`. If a determinant is zero, then the corresponding `sign` must be `0` and `logabsdet` must be `-infinity`. In all cases, the determinant must be equal to `sign * exp(logsabsdet)`. @@ -569,9 +569,9 @@ Computes the singular value decomposition `A = USV` of a matrix (or a stack of m - a namedtuple `(u, s, v)` whose - - first element must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the left singular vectors). The left singular vectors must be stored as columns. If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - second element must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - third element must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the right singular vectors). The right singular vectors must be stored as rows (i.e., the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - first element must have the field name `u` and must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the left singular vectors). The left singular vectors must be stored as columns. If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - second element must have the field name `s` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - third element must have the field name `v` and must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the right singular vectors). The right singular vectors must be stored as rows (i.e., the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. Each returned array must have the same floating-point data type as `x`. From cf5aa666017b8a8a2117aa1cb1770eb1cf841942 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 28 Jun 2021 13:55:39 -0700 Subject: [PATCH 016/551] Add specification for `__setitem__` (#172) --- spec/API_specification/array_object.md | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index fb711feda..93e806de3 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -1062,7 +1062,30 @@ Element-wise results must equal the results returned by the equivalent element-w (method-__setitem__)= ### \_\_setitem\_\_(self, key, value, /) -_TODO: dependent on the indexing specification._ +Sets `self[key]` to `value`. + +#### Parameters + +- **self**: _<array;>_ + + - array instance. + +- **key**: _Union\[ int, slice, ellipsis, Tuple\[ Union\[ int, slice, ellipsis ], ... ], <array> ]_ + + - index key. + +- **value**: _Union\[ int, float, bool, <array> ]_ + + - value(s) to set. Must be compatible with `self[key]` (see {ref}`broadcasting`). + +```{note} + +Setting array values must not affect the data type of `self`. + +When `value` is a Python scalar (i.e., `int`, `float`, `bool`), behavior must follow specification guidance on mixing arrays with Python scalars (see {ref}`type-promotion`). + +When `value` is an `array` of a different data type than `self`, how values are cast to the data type of `self` is implementation defined. +``` (method-__sub__)= ### \_\_sub\_\_(self, other, /) From 58d0f4711990b33aba08605cc92188278e3dcf3d Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 14:36:10 -0500 Subject: [PATCH 017/551] Add circleci config yml --- .circleci/config.yml | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 .circleci/config.yml diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 000000000..4b424507c --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,25 @@ +version: 2 + +# Aliases to reuse +_defaults: &defaults + docker: + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + - image: circleci/python:3.7.0 + working_directory: ~/repo + +jobs: + build_page: + <<: *defaults + steps: + - attach_workspace: + at: ~/ + + - run: + name: build docs + no_output_timeout: 25m + command: | + pip install -r requirements.txt + sphinx-build -b html -WT --keep-going spec build/latest -d doctrees + - store_artifacts: + path: build/latest From 9730dd5cc6a8de201537c8407e134f3ad6b3a9fc Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 8 Jul 2021 21:37:33 +0200 Subject: [PATCH 018/551] Add .circleci/config.yml From 3a367b7ee704ad5d5eaaca6b80e1dbb6e4267ebe Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:39:57 -0500 Subject: [PATCH 019/551] Fix config.yml --- .circleci/config.yml | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4b424507c..1809d6bdc 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,18 +8,20 @@ _defaults: &defaults - image: circleci/python:3.7.0 working_directory: ~/repo -jobs: - build_page: - <<: *defaults - steps: - - attach_workspace: - at: ~/ +workflows: + build: + jobs: + - build_page: + <<: *defaults + steps: + - attach_workspace: + at: ~/ - - run: - name: build docs - no_output_timeout: 25m - command: | - pip install -r requirements.txt - sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - - store_artifacts: - path: build/latest + - run: + name: build docs + no_output_timeout: 25m + command: | + pip install -r requirements.txt + sphinx-build -b html -WT --keep-going spec build/latest -d doctrees + - store_artifacts: + path: build/latest From 5265b6f2adc196736bbb8400fb7fdaff1c03c4e8 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Thu, 8 Jul 2021 15:42:38 -0500 Subject: [PATCH 020/551] Add .circleci/config.yml From 8871a29b4d452569b8abf6c4c788086074429bde Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:44:10 -0500 Subject: [PATCH 021/551] As example --- .circleci/config.yml | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1809d6bdc..4b424507c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,20 +8,18 @@ _defaults: &defaults - image: circleci/python:3.7.0 working_directory: ~/repo -workflows: - build: - jobs: - - build_page: - <<: *defaults - steps: - - attach_workspace: - at: ~/ +jobs: + build_page: + <<: *defaults + steps: + - attach_workspace: + at: ~/ - - run: - name: build docs - no_output_timeout: 25m - command: | - pip install -r requirements.txt - sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - - store_artifacts: - path: build/latest + - run: + name: build docs + no_output_timeout: 25m + command: | + pip install -r requirements.txt + sphinx-build -b html -WT --keep-going spec build/latest -d doctrees + - store_artifacts: + path: build/latest From 35e1cdb50e5f39eb2f6e855dc046b735ead21e3c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:45:42 -0500 Subject: [PATCH 022/551] Add workflows --- .circleci/config.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4b424507c..b6fcfeaaa 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -23,3 +23,9 @@ jobs: sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - store_artifacts: path: build/latest + +workflows: + version: 2 + default: + jobs: + - build_page From f3757655c5dd77acaa04cf414f59f3fc2dd89172 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:46:55 -0500 Subject: [PATCH 023/551] add pwd --- .circleci/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index b6fcfeaaa..38ad92187 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,6 +19,7 @@ jobs: name: build docs no_output_timeout: 25m command: | + pwd pip install -r requirements.txt sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - store_artifacts: From 34beefe2420ebc8c21af1bf2586e126476a9656f Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:47:34 -0500 Subject: [PATCH 024/551] add ls --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 38ad92187..665f0daeb 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,7 +19,7 @@ jobs: name: build docs no_output_timeout: 25m command: | - pwd + ls pip install -r requirements.txt sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - store_artifacts: From 2718bfc15539c6ad14be8592794aa7b95aff82f9 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:49:29 -0500 Subject: [PATCH 025/551] Checkout --- .circleci/config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 665f0daeb..4f3a78c1d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,6 +12,8 @@ jobs: build_page: <<: *defaults steps: + - checkout + - attach_workspace: at: ~/ From cebb3e3206af62b393808d9c008fc5a15bf9bb1f Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:50:29 -0500 Subject: [PATCH 026/551] add --user --- .circleci/config.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4f3a78c1d..1cbeab826 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,8 +21,7 @@ jobs: name: build docs no_output_timeout: 25m command: | - ls - pip install -r requirements.txt + pip install --user -r requirements.txt sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - store_artifacts: path: build/latest From ce6df71e9cbf0c788e52232934644a9924e005a0 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:51:20 -0500 Subject: [PATCH 027/551] sudo --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1cbeab826..f0471e873 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,7 +21,7 @@ jobs: name: build docs no_output_timeout: 25m command: | - pip install --user -r requirements.txt + sudo pip install -r requirements.txt sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - store_artifacts: path: build/latest From 3fc0ba0f675b325d05156972901de8705fc892f0 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:57:34 -0500 Subject: [PATCH 028/551] add preview --- .github/workflows/preview.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/preview.yml diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 000000000..ced637494 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,17 @@ +on: [status] +jobs: + circleci_artifacts_redirector_job: + runs-on: ubuntu-latest + name: Run CircleCI artifacts redirector + steps: + - name: GitHub Action step + id: step1 + uses: larsoner/circleci-artifacts-redirector-action@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + artifact-path: 0/build/latest/index.html + circleci-jobs: build_page + job-title: Check the rendered docs here! + - name: Check the URL + run: | + curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA \ No newline at end of file From c363916c695b4cfab04db1b65f97e3eeacc90fa6 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 15:58:56 -0500 Subject: [PATCH 029/551] change name --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index ced637494..46e9a1ef9 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -12,6 +12,6 @@ jobs: artifact-path: 0/build/latest/index.html circleci-jobs: build_page job-title: Check the rendered docs here! - - name: Check the URL + - name: Array API preview run: | curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA \ No newline at end of file From e14d9a7f5539ceb163e95cd82889155aac29ff26 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 8 Jul 2021 16:01:24 -0500 Subject: [PATCH 030/551] Add preview to array API page --- .circleci/config.yml | 10 ++++++++-- .github/workflows/preview.yml | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/preview.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 4b424507c..cb1031906 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -12,14 +12,20 @@ jobs: build_page: <<: *defaults steps: + - checkout - attach_workspace: at: ~/ - - run: name: build docs no_output_timeout: 25m command: | - pip install -r requirements.txt + sudo pip install -r requirements.txt sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - store_artifacts: path: build/latest + +workflows: + version: 2 + default: + jobs: + - build_page \ No newline at end of file diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml new file mode 100644 index 000000000..46e9a1ef9 --- /dev/null +++ b/.github/workflows/preview.yml @@ -0,0 +1,17 @@ +on: [status] +jobs: + circleci_artifacts_redirector_job: + runs-on: ubuntu-latest + name: Run CircleCI artifacts redirector + steps: + - name: GitHub Action step + id: step1 + uses: larsoner/circleci-artifacts-redirector-action@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + artifact-path: 0/build/latest/index.html + circleci-jobs: build_page + job-title: Check the rendered docs here! + - name: Array API preview + run: | + curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA \ No newline at end of file From b9ae18712f36e00398f60c52194e5c0ccfdeda52 Mon Sep 17 00:00:00 2001 From: Lezcano Date: Sat, 10 Jul 2021 10:41:26 +0100 Subject: [PATCH 031/551] Remove raises section for matrix_power (#219) --- spec/extensions/linear_algebra_functions.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 423e17b85..4e1b93567 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -323,11 +323,6 @@ Raises a square matrix (or a stack of square matrices) `x` to an integer power ` - if `n` is equal to zero, an array containing the identity matrix for each square matrix. If `n` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of `n`, provided that each square matrix is invertible. If `n` is greater than zero, an array containing the result of raising each square matrix to the power `n`. The returned array must have the same shape as `x` and a floating-point data type determined by {ref}`type-promotion`. -#### Raises - -- if the innermost two dimensions of `x` are not the same size (i.e., form square matrices). -- if `n` is less than zero and a square matrix is not invertible. - (function-linalg-matrix_rank)= ### linalg.matrix_rank(x, /, *, rtol=None) @@ -648,4 +643,4 @@ Alias for {ref}`function-transpose`. (function-linalg-vecdot)= ### linalg.vecdot(x1, x2, /, *, axis=None) -Alias for {ref}`function-vecdot`. \ No newline at end of file +Alias for {ref}`function-vecdot`. From 780da6e17e7da253fea9dc8e0c7334fcce675da8 Mon Sep 17 00:00:00 2001 From: Lezcano Date: Thu, 15 Jul 2021 21:12:46 +0100 Subject: [PATCH 032/551] Change v to vh in SVD (#218) --- spec/extensions/linear_algebra_functions.md | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 4e1b93567..00e05ab86 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -201,7 +201,7 @@ Returns the eigenvalues and eigenvectors of a symmetric matrix (or a stack of sy - **out**: _Tuple\[ <array> ]_ - a namedtuple (`eigenvalues`, `eigenvectors`) whose - + - first element must have the field name `eigenvalues` and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape `(..., M)`. - second element have have the field name `eigenvectors` and must be an array where the columns of the inner most matrices contain the computed eigenvectors. The array containing the eigenvectors must have shape `(..., M, M)`. @@ -291,7 +291,7 @@ Returns the least-squares solution to a linear matrix equation `Ax = b`. - **out**: _Tuple\[ <array>, <array>, <array>, <array> ]_ - a namedtuple `(x, residuals, rank, s)` whose - + - first element must have the field name `x` and must be an array containing the least-squares solution for each `MxN` matrix in `x1`. The array containing the solutions must have shape `(N, K)` and must have a floating-point data type determined by {ref}`type-promotion`. - second element must have the field name `residuals` and must be an array containing the sum of squares residuals (i.e., the squared Euclidean 2-norm for each column in `b - Ax`). The array containing the residuals must have shape `(K,)` and must have a floating-point data type determined by {ref}`type-promotion`. - third element must have the field name `rank` and must be an array containing the effective rank of each `MxN` matrix. The array containing the ranks must have shape `shape(x1)[:-2]` and must have an integer data type. @@ -300,7 +300,7 @@ Returns the least-squares solution to a linear matrix equation `Ax = b`. (function-linalg-matmul)= ### linalg.matmul(x1, x2, /) -Alias for {ref}`function-matmul`. +Alias for {ref}`function-matmul`. (function-linalg-matrix_power)= ### linalg.matrix_power(x, n, /) @@ -453,7 +453,7 @@ Computes the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of square ma - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - + - relative tolerance for small singular values. Singular values less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. #### Returns @@ -514,10 +514,10 @@ The purpose of this function is to calculate the determinant more accurately whe - **out**: _Tuple\[ <array>, <array> ]_ - a namedtuple (`sign`, `logabsdet`) whose - + - first element must have the field name `sign` and must be an array containing a number representing the sign of the determinant for each square matrix. - second element must have the field name `logabsdet` and must be an array containing the determinant for each square matrix. - + For a real matrix, the sign of the determinant must be either `1`, `0`, or `-1`. If a determinant is zero, then the corresponding `sign` must be `0` and `logabsdet` must be `-infinity`. In all cases, the determinant must be equal to `sign * exp(logsabsdet)`. Each returned array must have shape `shape(x)[:-2]` and a floating-point data type determined by {ref}`type-promotion`. @@ -546,7 +546,7 @@ Returns the solution to the system of linear equations represented by the well-d (function-linalg-svd)= ### linalg.svd(x, /, *, full_matrices=True) -Computes the singular value decomposition `A = USV` of a matrix (or a stack of matrices) `x`. +Computes the singular value decomposition `A = USVh` of a matrix (or a stack of matrices) `x`. #### Parameters @@ -556,17 +556,17 @@ Computes the singular value decomposition `A = USV` of a matrix (or a stack of m - **full_matrices**: _bool_ - - If `True`, compute full-sized `u` and `v`, such that `u` has shape `(..., M, M)` and `v` has shape `(..., N, N)`. If `False`, compute on the leading `K` singular vectors, such that `u` has shape `(..., M, K)` and `v` has shape `(..., K, N)` and where `K = min(M, N)`. Default: `True`. + - If `True`, compute full-sized `u` and `vh`, such that `u` has shape `(..., M, M)` and `vh` has shape `(..., N, N)`. If `False`, compute on the leading `K` singular vectors, such that `u` has shape `(..., M, K)` and `vh` has shape `(..., K, N)` and where `K = min(M, N)`. Default: `True`. #### Returns - **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ - - a namedtuple `(u, s, v)` whose - + - a namedtuple `(u, s, vh)` whose + - first element must have the field name `u` and must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the left singular vectors). The left singular vectors must be stored as columns. If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - second element must have the field name `s` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - third element must have the field name `v` and must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the right singular vectors). The right singular vectors must be stored as rows (i.e., the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - third element must have the field name `vh` and must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the right singular vectors). The right singular vectors must be stored as rows (i.e., the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. Each returned array must have the same floating-point data type as `x`. From 7e720c8bbb1c911d386b202bdf6da718c7ac96a9 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 19 Jul 2021 09:56:57 -0500 Subject: [PATCH 033/551] Add review changes --- .../extensions/fourier_transform_functions.md | 281 +++++++++--------- 1 file changed, 140 insertions(+), 141 deletions(-) diff --git a/spec/extensions/fourier_transform_functions.md b/spec/extensions/fourier_transform_functions.md index 5153b354e..6681e2597 100644 --- a/spec/extensions/fourier_transform_functions.md +++ b/spec/extensions/fourier_transform_functions.md @@ -13,11 +13,11 @@ A conforming implementation of the array API standard must provide and support t ## Objects in API - + (function-fft)= ### fft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional discrete Fourier transform. +Computes the one-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `fft(ifft(a)) == a`. #### Parameters @@ -27,7 +27,7 @@ Computes the one-dimensional discrete Fourier transform. - **n**: _int_ - - Length of the transformed axis of the output. If it is `None`, the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the Fourier transform. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ @@ -51,33 +51,46 @@ Computes the one-dimensional discrete Fourier transform. #### Raises -- If `axis` is larger than the last axis of `a`. +- If `axis` is not a valid axis of `a`. -(function-fftfreq)= -### fftfreq(n, /, *, d=1.0) - -Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length `n` and length unit of `d` the frequencies are described as: +(function-ifft)= +### ifft(a, /, *, n=None, axis=-1, norm='backward') -``` -f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even -f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd -``` +Computes the one-dimensional inverse discrete Fourier transform. #### Parameters +- **a**: _<array>_ + + - Input array. + - **n**: _int_ - - Window length. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. -- **d**: _float_ +- **axis**: _int_ - - Sample spacing between individual samples of the Fourier transform input. Default: `1.0`. + - Axis used to compute the inverse Fourier transform. If it is not specified, the last axis is used. Default: `-1`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: Normalize by `1/n`. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: No normalization. + + Default: `'backward'` #### Returns - **out**: _<array>_ - - An array of length `n` containing the sample frequencies. + - An array transformed along the axis indicated by the `axis` keyword. + +#### Raises + +- If `axis` is not a valid axis of `a`. (function-fftn)= ### fftn(a, /, *, s=None, axes=None, norm='backward') @@ -92,11 +105,11 @@ Computes the n-dimensional discrete Fourier transform. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the fast Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, the length of the input along the axis given by the `axes` keyword. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + - Axes over which to compute the Fourier transform. If not specified, the last `len(s)` axes are used, or all axes if `s` is not specified either. Default: `None`. - **norm**: _str_ @@ -116,34 +129,53 @@ Computes the n-dimensional discrete Fourier transform. #### Raises -- If `s` and `axes` have a different length. +- If `s` and `axes` have different lengths. - If an element of `axes` is larger than the number of axes of `a`. -(function-fftshift)= -### fftshift(x, /, *, axes=None) +(function-ifftn)= +### ifftn(a, /, *, s=None, axes=None, norm='backward') -Reorders n-dimensional FTT data to have negative frequency terms first. In this way, the zero-frequency component shifts to the center of the spectrum. Note that `out[0]` is the Nyquist component only if the length of the input is even. +Computes the n-dimensional inverse discrete Fourier transform. #### Parameters -- **x**: _<array>_ +- **a**: _<array>_ - Input array. -- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to shift. If not specified, it shifts all axes. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the `axes` keyword. Default: `None`. + +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ + + - Axes over which to compute the inverse Fourier transform. If not specified, the last `len(s)` axes are used, or all axes if `s` is not specified either. Default: `None`. + +- **norm**: _str_ + + - Specify the normalization mode. Should be one of the following modes: + + - `'backward'`: Normalize by `1/n`. + - `'ortho'`: Normalize by `1/sqrt(n)` + - `'forward'`: No normalization. + + Default: `'backward'` #### Returns - **out**: _<array>_ - - The shifted array. + - An array transformed along the axes indicated by the `axes` keyword. -(function-hfft)= -### hfft(a, /, *, n=None, axis=-1, norm='backward') +#### Raises -Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. +- If `s` and `axes` have different lengths. +- If an element of `axes` is larger than the number of axes of `a`. + +(function-rfft)= +### rfft(a, /, *, n=None, axis=-1, norm='backward') + +Computes the one-dimensional discrete Fourier transform for real-valued input. #### Parameters @@ -153,11 +185,11 @@ Computes the one-dimensional discrete Fourier transform of a signal with Hermiti - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the input array. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. - **axis**: _int_ - - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ @@ -173,16 +205,16 @@ Computes the one-dimensional discrete Fourier transform of a signal with Hermiti - **out**: _<array>_ - - A transformed array. + - An array transformed along the axis indicated by the `axis` keyword. #### Raises -- If `axis` is larger than the last axis of `a`. +- If `axis` is not a valid axis of `a`. -(function-ifft)= -### ifft(a, /, *, n=None, axis=-1, norm='backward') +(function-irfft)= +### irfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional inverse discrete Fourier transform. +Computes the one-dimensional inverse discrete Fourier transform for real-valued input. #### Parameters @@ -192,11 +224,11 @@ Computes the one-dimensional inverse discrete Fourier transform. - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the IFourier transform. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ - - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ @@ -216,12 +248,12 @@ Computes the one-dimensional inverse discrete Fourier transform. #### Raises -- If `axis` is larger than the last axis of `a`. +- If `axis` is not a valid axis of `a`. -(function-ifftn)= -### ifftn(a, /, *, s=None, axes=None, norm='backward') +(function-rfftn)= +### rfftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional inverse discrete Fourier transform. +Computes the n-dimensional discrete Fourier transform for real-valued input. #### Parameters @@ -231,19 +263,19 @@ Computes the n-dimensional inverse discrete Fourier transform. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the real Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axes over which to compute the inverse Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + - Axes over which to compute the Fourier transform. If not specified, the last `len(s)` axes are used, or all axes if `s` is not specified either. Default: `None`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: Normalize by `1/n`. + - `'backward'`: No normalization. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. + - `'forward'`: Normalize by `1/n`. Default: `'backward'` @@ -255,34 +287,13 @@ Computes the n-dimensional inverse discrete Fourier transform. #### Raises -- If `s` and `axes` have a different length. +- If `s` and `axes` have different lengths. - If an element of `axes` is larger than the number of axes of `a`. -(function-ifftshift)= -### ifftshift(x, /, *, axes=None) - -Inverse of `fftshift`. - -#### Parameters - -- **x**: _<array>_ - - - Input array. - -- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to calculate. If not specified, it shifts all axes. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - The shifted array. - -(function-ihfft)= -### ihfft(a, /, *, n=None, axis=-1, norm='backward') +(function-irfftn)= +### irfftn(a, /, *, s=None, axes=None, norm='backward') -Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. +Computes the n-dimensional inverse discrete Fourier transform for real-valued input. #### Parameters @@ -290,13 +301,13 @@ Computes the one-dimensional inverse discrete Fourier transform of a signal with - Input array. -- **n**: _int_ +- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. -- **axis**: _int_ +- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axes over which to compute the inverse Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. - **norm**: _str_ @@ -312,16 +323,17 @@ Computes the one-dimensional inverse discrete Fourier transform of a signal with - **out**: _<array>_ - - A transformed array. + - An array transformed along the axes indicated by the `axes` keyword. #### Raises -- If `axis` is larger than the last axis of `a`. +- If `s` and `axes` have different lengths. +- If an element of `axes` is larger than the number of axes of `a`. -(function-irfft)= -### irfft(a, /, *, n=None, axis=-1, norm='backward') +(function-hfft)= +### hfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional inverse discrete Fourier transform for real-valued input. +Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. #### Parameters @@ -331,19 +343,19 @@ Computes the one-dimensional inverse discrete Fourier transform for real-valued - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ - - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. + - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ - Specify the normalization mode. Should be one of the following modes: - - `'backward'`: Normalize by `1/n`. + - `'backward'`: No normalization. - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. + - `'forward'`: Normalize by `1/n`. Default: `'backward'` @@ -351,16 +363,16 @@ Computes the one-dimensional inverse discrete Fourier transform for real-valued - **out**: _<array>_ - - An array transformed along the axis indicated by the `axis` keyword. + - A transformed array. #### Raises -- If `axis` is larger than the last axis of `a`. +- If `axis` is not a valid axis of `a`. -(function-irfftn)= -### irfftn(a, /, *, s=None, axes=None, norm='backward') +(function-ihfft)= +### ihfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the n-dimensional inverse discrete Fourier transform for real-valued input. +Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. #### Parameters @@ -368,13 +380,13 @@ Computes the n-dimensional inverse discrete Fourier transform for real-valued in - Input array. -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ +- **n**: _int_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ +- **axis**: _int_ - - Axes over which to compute the inverse Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. + - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - **norm**: _str_ @@ -390,52 +402,37 @@ Computes the n-dimensional inverse discrete Fourier transform for real-valued in - **out**: _<array>_ - - An array transformed along the axes indicated by the `axes` keyword. + - A transformed array. #### Raises -- If `s` and `axes` have a different length. -- If an element of `axes` is larger than the number of axes of `a`. +- If `axis` is not a valid axis of `a`. +(function-fftfreq)= +### fftfreq(n, /, *, d=1.0) -(function-rfft)= -### rfft(a, /, *, n=None, axis=-1, norm='backward') +Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length `n` and length unit of `d` the frequencies are described as: -Computes the one-dimensional discrete Fourier transform for real-valued input. +``` +f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even +f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd +``` #### Parameters -- **a**: _<array>_ - - - Input array. - - **n**: _int_ - - Length of the input array. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. - -- **axis**: _int_ - - - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: + - Window length. - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. +- **d**: _float_ - Default: `'backward'` + - Sample spacing between individual samples of the Fourier transform input. Default: `1.0`. #### Returns - **out**: _<array>_ - - An array transformed along the axis indicated by the `axis` keyword. - -#### Raises - -- If `axis` is larger than the last axis of `a`. + - An array of length `n` containing the sample frequencies. (function-rfftfreq)= ### rfftfreq(n, /, *, d=1.0) @@ -465,42 +462,44 @@ The Nyquist frequency component is considered to be positive. - An array of length `n` containing the sample frequencies. -(function-rfftn)= -### rfftn(a, /, *, s=None, axes=None, norm='backward') +(function-fftshift)= +### fftshift(x, /, *, axes=None) -Computes the n-dimensional discrete Fourier transform for real-valued input. +Reorders n-dimensional FTT data to have negative frequency terms first. In this way, the zero-frequency component shifts to the center of the spectrum. Note that `out[0]` is the Nyquist component only if the length of the input is even. #### Parameters -- **a**: _<array>_ +- **x**: _<array>_ - Input array. -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ +- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the real Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Axes over which to shift. If not specified, it shifts all axes. Default: `None`. -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ +#### Returns - - Axes over which to compute the Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. +- **out**: _<array>_ -- **norm**: _str_ + - The shifted array. - - Specify the normalization mode. Should be one of the following modes: +(function-ifftshift)= +### ifftshift(x, /, *, axes=None) - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. +Inverse of `fftshift`. - Default: `'backward'` +#### Parameters -#### Returns +- **x**: _<array>_ -- **out**: _<array>_ + - Input array. - - An array transformed along the axes indicated by the `axes` keyword. +- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ -#### Raises + - Axes over which to calculate. If not specified, it shifts all axes. Default: `None`. + +#### Returns -- If `s` and `axes` have a different length. -- If an element of `axes` is larger than the number of axes of `a`. \ No newline at end of file +- **out**: _<array>_ + + - The shifted array. From 70560890d481f62e6ee498c9d58afcbd87f325c4 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 21 Jul 2021 15:02:56 -0600 Subject: [PATCH 034/551] Add i8 to the mixed-type promotion table (#233) --- spec/API_specification/type_promotion.md | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/API_specification/type_promotion.md b/spec/API_specification/type_promotion.md index e2ec506e0..ae1faac44 100644 --- a/spec/API_specification/type_promotion.md +++ b/spec/API_specification/type_promotion.md @@ -70,6 +70,7 @@ where | **i1** | i2 | i4 | i8 | | **i2** | i2 | i4 | i8 | | **i4** | i4 | i4 | i8 | +| **i8** | i8 | i8 | i8 | ### Floating-point type promotion table From 0efc3a3074afae1687559565e87d21d6d8b3ac18 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 12 Aug 2021 17:58:30 -0500 Subject: [PATCH 035/551] Add review changes --- .../extensions/fourier_transform_functions.md | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/spec/extensions/fourier_transform_functions.md b/spec/extensions/fourier_transform_functions.md index 6681e2597..51fb34c82 100644 --- a/spec/extensions/fourier_transform_functions.md +++ b/spec/extensions/fourier_transform_functions.md @@ -17,7 +17,7 @@ A conforming implementation of the array API standard must provide and support t (function-fft)= ### fft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `fft(ifft(a)) == a`. +Computes the one-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifft(fft(a)) == a` within numerical accuracy. #### Parameters @@ -47,7 +47,7 @@ Computes the one-dimensional discrete Fourier transform. The expected behavior i - **out**: _<array>_ - - An array transformed along the axis indicated by the `axis` keyword. + - A complex-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n//2+1`. #### Raises @@ -56,7 +56,7 @@ Computes the one-dimensional discrete Fourier transform. The expected behavior i (function-ifft)= ### ifft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional inverse discrete Fourier transform. +Computes the one-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifft(fft(a)) == a` within numerical accuracy. #### Parameters @@ -86,7 +86,7 @@ Computes the one-dimensional inverse discrete Fourier transform. - **out**: _<array>_ - - An array transformed along the axis indicated by the `axis` keyword. + - A complex-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n//2+1`. #### Raises @@ -95,7 +95,7 @@ Computes the one-dimensional inverse discrete Fourier transform. (function-fftn)= ### fftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional discrete Fourier transform. +Computes the n-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifftn(fftn(a)) == a` within numerical accuracy. #### Parameters @@ -105,7 +105,7 @@ Computes the n-dimensional discrete Fourier transform. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, the length of the input along the axis given by the `axes` keyword. Default: `None`. + - Size of each transformed axis of the output. If given, each axis `i` will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, the shape of the input along the axes given by the `axes` keyword. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ @@ -130,12 +130,12 @@ Computes the n-dimensional discrete Fourier transform. #### Raises - If `s` and `axes` have different lengths. -- If an element of `axes` is larger than the number of axes of `a`. +- If `axes` contains any invalid axis of `a`. (function-ifftn)= ### ifftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional inverse discrete Fourier transform. +Computes the n-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifftn(fftn(a)) == a` within numerical accuracy. #### Parameters @@ -170,12 +170,12 @@ Computes the n-dimensional inverse discrete Fourier transform. #### Raises - If `s` and `axes` have different lengths. -- If an element of `axes` is larger than the number of axes of `a`. +- If `axes` contains any invalid axis of `a`. (function-rfft)= ### rfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional discrete Fourier transform for real-valued input. +Computes the one-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, `irfft(rfft(a), n=a.shape[axis]) == a` within numerical accuracy. #### Parameters @@ -185,7 +185,7 @@ Computes the one-dimensional discrete Fourier transform for real-valued input. - **n**: _int_ - - Length of the input array. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. + - Length of the transformed axis of the *input*. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. - **axis**: _int_ @@ -205,7 +205,7 @@ Computes the one-dimensional discrete Fourier transform for real-valued input. - **out**: _<array>_ - - An array transformed along the axis indicated by the `axis` keyword. + - A complex-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n//2+1`. #### Raises @@ -214,7 +214,7 @@ Computes the one-dimensional discrete Fourier transform for real-valued input. (function-irfft)= ### irfft(a, /, *, n=None, axis=-1, norm='backward') -Computes the one-dimensional inverse discrete Fourier transform for real-valued input. +Computes the one-dimensional inverse of `rfft`. The expected behavior includes a round-trip transform using the inverse function, `irfft(rfft(a), n=a.shape[axis]) == a` within numerical accuracy. #### Parameters @@ -224,7 +224,7 @@ Computes the one-dimensional inverse discrete Fourier transform for real-valued - **n**: _int_ - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. + - Length of the transformed axis of the *output*. If given, the input will be either zero-padded or trimmed to `n//2+1` before computing the inverse of `rfft`. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - **axis**: _int_ @@ -244,7 +244,7 @@ Computes the one-dimensional inverse discrete Fourier transform for real-valued - **out**: _<array>_ - - An array transformed along the axis indicated by the `axis` keyword. + - A real-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n` (if given) or `2 * (m - 1)`. #### Raises @@ -253,7 +253,7 @@ Computes the one-dimensional inverse discrete Fourier transform for real-valued (function-rfftn)= ### rfftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional discrete Fourier transform for real-valued input. +Computes the n-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, `irfftn(rfftn(a), s=a.shape) == a` within numerical accuracy. #### Parameters @@ -263,7 +263,7 @@ Computes the n-dimensional discrete Fourier transform for real-valued input. - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the real Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the output. If given, each axis `i` will be either zero-padded or trimmed to the length `s[i]` before computing the real Fourier transform. Otherwise, the shape of the input along the axes given by the `axes` keyword. The last element `s[-1]` is for computing `rfft(a[axes[-1]], n=s[-1])` whereas other elements for `fft(a[axes[i]], n=s[i])`. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ @@ -283,17 +283,17 @@ Computes the n-dimensional discrete Fourier transform for real-valued input. - **out**: _<array>_ - - An array transformed along the axes indicated by the `axes` keyword. + - A complex-valued array transformed along the axes indicated by the `axes` keyword. The length along the last transformed axis is `s[-1]//2+1` and along other axes `s[i]`. #### Raises - If `s` and `axes` have different lengths. -- If an element of `axes` is larger than the number of axes of `a`. +- If `axes` contains any invalid axis of `a`. (function-irfftn)= ### irfftn(a, /, *, s=None, axes=None, norm='backward') -Computes the n-dimensional inverse discrete Fourier transform for real-valued input. +Computes the n-dimensional inverse of `rfftn`. The expected behavior includes a round-trip transform using the inverse function, `irfftn(rfftn(a), s=a.shape) == a` within numerical accuracy. #### Parameters @@ -303,7 +303,7 @@ Computes the n-dimensional inverse discrete Fourier transform for real-valued in - **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, no padding will be performed in each dimension. Default: `None`. + - Size of each transformed axis of the *output*. If given, the last axis will be either zero-padded or trimmed to `s[-1]//2+1`, whereas all other axes `i` are either zero-padded or trimmed to the length `s[i]`, before computing the inverse of `rfftn`. Otherwise, the last axis is either zero-padded or trimmed to `2 * (m - 1)`, where `m` is the length of the input along the axis, and all other axes use the input shape. The last element `s[-1]` is for computing `irfft(a[axes[-1]], n=s[-1])` whereas other elements for `ifft(a[axes[i]], n=s[i])`. Default: `None`. - **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ @@ -323,12 +323,12 @@ Computes the n-dimensional inverse discrete Fourier transform for real-valued in - **out**: _<array>_ - - An array transformed along the axes indicated by the `axes` keyword. + - A real-valued array transformed along the axes indicated by the `axes` keyword. The length along the last transformed axis is `s[-1]` (if given) or `2 * (m - 1)`, and all other axes `s[i]`. #### Raises - If `s` and `axes` have different lengths. -- If an element of `axes` is larger than the number of axes of `a`. +- If `axes` contains any invalid axis of `a`. (function-hfft)= ### hfft(a, /, *, n=None, axis=-1, norm='backward') From 27bdfbebceeb7af5a8cedff65913a5273e086ada Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Fri, 13 Aug 2021 01:45:18 -0600 Subject: [PATCH 036/551] Fix the logaddexp special cases (#239) As previously written, they would fail in the test suite because of ambiguity about the value of logaddexp(nan, inf). --- spec/API_specification/elementwise_functions.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 01a7a35d9..97c77c6bc 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -944,8 +944,9 @@ each element `x1_i` of the input array `x1` with the respective element `x2_i` o For floating-point operands, -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If either `x1_i` or `x2_i` is `+infinity`, the result is `+infinity`. +- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. +- If `x1_i` is `+infinity` and `x2_i` is not `NaN`, the result is `+infinity`. +- If `x1_i` is not `NaN` and `x2_i` is `+infinity`, the result is `+infinity`. #### Parameters From 96e40ad8e13e534683d7ad5dcd7930514ef1e73f Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 19 Aug 2021 14:40:36 -0700 Subject: [PATCH 037/551] Remove `axisN` eyword arguments from linalg.diag and linalg.trace (#241) --- spec/extensions/linear_algebra_functions.md | 34 +++++---------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 00e05ab86..3d51dca0d 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -140,23 +140,15 @@ Returns the determinant of a square matrix (or stack of square matrices) `x`. - if `x` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as `x`. (function-linalg-diagonal)= -### linalg.diagonal(x, /, *, axis1=0, axis2=1, offset=0) +### linalg.diagonal(x, /, *, offset=0) -Returns the specified diagonals. If `x` has more than two dimensions, then the axes (dimensions) specified by `axis1` and `axis2` are used to determine the two-dimensional sub-arrays from which to return diagonals. +Returns the specified diagonals of a matrix (or a stack of matrices) `x`. #### Parameters - **x**: _<array>_ - - input array. Must have at least `2` dimensions. - -- **axis1**: _int_ - - - first axis (dimension) with respect to which to take diagonal. Default: `0`. - -- **axis2**: _int_ - - - second axis (dimension) with respect to which to take diagonal. Default: `1`. + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. - **offset**: _int_ @@ -172,7 +164,7 @@ Returns the specified diagonals. If `x` has more than two dimensions, then the a - **out**: _<array>_ - - if `x` is a two-dimensional array, a one-dimensional array containing the diagonal; otherwise, a multi-dimensional array containing the diagonals and whose shape is determined by removing `axis1` and `axis2` and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as `x`. + - an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as `x`. (function-linalg-eig)= ### linalg.eig() @@ -593,23 +585,15 @@ Computes the singular values of a matrix (or a stack of matrices) `x`. - an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. The returned array must have the same floating-point data type as `x`. (function-linalg-trace)= -### linalg.trace(x, /, *, axis1=0, axis2=1, offset=0) +### linalg.trace(x, /, *, offset=0) -Returns the sum along the specified diagonals. If `x` has more than two dimensions, then the axes (dimensions) specified by `axis1` and `axis2` are used to determine the two-dimensional sub-arrays for which to compute the trace. +Returns the sum along the specified diagonals of a matrix (or a stack of matrices) `x`. #### Parameters - **x**: _<array>_ - - input array. Must have at least `2` dimensions. Should have a numeric data type. - -- **axis1**: _int_ - - - first axis (dimension) with respect to which to compute the trace. Default: `0`. - -- **axis2**: _int_ - - - second axis (dimension) with respect to which to compute the trace. Default: `1`. + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a numeric data type. - **offset**: _int_ @@ -625,9 +609,7 @@ Returns the sum along the specified diagonals. If `x` has more than two dimensio - **out**: _<array>_ - - if `x` is a two-dimensional array, the returned array must be a zero-dimensional array containing the trace; otherwise, the returned array must be a multi-dimensional array containing the traces. - - The shape of a multi-dimensional output array is determined by removing `axis1` and `axis2` and storing the traces in the last array dimension. For example, if `x` has rank `k` and shape `(I, J, K, ..., L, M, N)` and `axis1=-2` and `axis1=-1`, then a multi-dimensional output array has rank `k-2` and shape `(I, J, K, ..., L)` where + - an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if `x` has rank `k` and shape `(I, J, K, ..., L, M, N)`, then an output array has rank `k-2` and shape `(I, J, K, ..., L)` where ```text out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) From 30a317fac0036b90700109b2eb0b82569072fb8c Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 19 Aug 2021 16:50:42 -0500 Subject: [PATCH 038/551] Some improvements to type hints (#230) * Fix alphabetical function ordering in the linear algebra extension * Update some type hints in the spec These come from comments on the NumPy pull request https://github.com/numpy/numpy/pull/18585. * Clarify that the where() result type is only based on the last two arguments * Use Literal[] for the qr() mode argument type hint * Add bool and int to the asarray type hints * Fix a typo in the __setitem__ annotations --- spec/API_specification/array_object.md | 6 +++--- spec/API_specification/creation_functions.md | 2 +- spec/API_specification/manipulation_functions.md | 4 ++-- spec/API_specification/searching_functions.md | 6 +++--- spec/extensions/linear_algebra_functions.md | 14 +++++++------- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 93e806de3..dcf78228b 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -780,7 +780,7 @@ The `matmul` function must implement the same semantics as the built-in `@` oper - **self**: _<array>_ - - array instance. Should have a numeric data type. Must have at least one dimension. If `self` is one-dimensional having shape `(M)` and `other` has more than one dimension, `self` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `self` has more than one dimension (including after vector-to-matrix promotion), `self` must be compatible with `other` (see {ref}`broadcasting`). If `self` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. + - array instance. Should have a numeric data type. Must have at least one dimension. If `self` is one-dimensional having shape `(M)` and `other` has more than one dimension, `self` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `self` has more than one dimension (including after vector-to-matrix promotion), `self` must be compatible with `other` (see {ref}`broadcasting`). If `self` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - **other**: _<array>_ @@ -809,7 +809,7 @@ The `matmul` function must implement the same semantics as the built-in `@` oper - if either `self` or `other` is a zero-dimensional array. - if `self` is a one-dimensional array having shape `(N)`, `other` is a one-dimensional array having shape `(M)`, and `N != M`. -- if `self` is an array having shape `(..., M, K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. +- if `self` is an array having shape `(..., M, K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. (method-__mod__)= ### \_\_mod\_\_(self, other, /) @@ -1066,7 +1066,7 @@ Sets `self[key]` to `value`. #### Parameters -- **self**: _<array;>_ +- **self**: _<array>_ - array instance. diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index 8b1bec16e..da7b250b4 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -57,7 +57,7 @@ Convert the input to an array. #### Parameters -- **obj**: _Union\[ float, NestedSequence\[ bool | int | float ], SupportsDLPack, SupportsBufferProtocol ]_ +- **obj**: _Union\[ <array>, bool, int, float, NestedSequence\[ bool | int | float ], SupportsDLPack, SupportsBufferProtocol ]_ - Object to be converted to an array. Can be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting DLPack or the Python buffer protocol. diff --git a/spec/API_specification/manipulation_functions.md b/spec/API_specification/manipulation_functions.md index ae8499370..e1e0e98ea 100644 --- a/spec/API_specification/manipulation_functions.md +++ b/spec/API_specification/manipulation_functions.md @@ -19,7 +19,7 @@ Joins a sequence of arrays along an existing axis. #### Parameters -- **arrays**: _Tuple\[ <array>, ... ]_ +- **arrays**: _Union\[Tuple\[ <array>, ... ], List\[ <array> ] ]_ - input arrays to join. The arrays must have the same shape, except in the dimension specified by `axis`. @@ -154,7 +154,7 @@ Joins a sequence of arrays along a new axis. #### Parameters -- **arrays**: _Tuple\[ <array>, ... ]_ +- **arrays**: _Union\[Tuple\[ <array>, ... ], List\[ <array> ] ]_ - input arrays to join. Each array must have the same shape. diff --git a/spec/API_specification/searching_functions.md b/spec/API_specification/searching_functions.md index 3ad2ae8bb..f0311b8b7 100644 --- a/spec/API_specification/searching_functions.md +++ b/spec/API_specification/searching_functions.md @@ -27,7 +27,7 @@ Returns the indices of the maximum values along a specified axis. When the maxim - input array. -- **axis**: _int_ +- **axis**: _Optional\[ int ]_ - axis along which to search. If `None`, the function must return the index of the maximum value of the flattened array. Default: `None`. @@ -52,7 +52,7 @@ Returns the indices of the minimum values along a specified axis. When the minim - input array. -- **axis**: _int_ +- **axis**: _Optional\[ int ]_ - axis along which to search. If `None`, the function must return the index of the minimum value of the flattened array. Default: `None`. @@ -112,4 +112,4 @@ Returns elements chosen from `x1` or `x2` depending on `condition`. - **out**: _<array>_ - - an array with elements from `x1` where `condition` is `True`, and elements from `x2` elsewhere. The returned array must have a data type determined by {ref}`type-promotion` rules. + - an array with elements from `x1` where `condition` is `True`, and elements from `x2` elsewhere. The returned array must have a data type determined by {ref}`type-promotion` rules with the arrays `x1` and `x2`. diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 3d51dca0d..b2f59082b 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -465,7 +465,7 @@ Computes the qr factorization of a matrix (or a stack of matrices), where `q` is - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. -- **mode**: _str_ +- **mode**: _Literal\[ 'reduced', 'complete' ]_ - factorization mode. Should be one of the following modes: @@ -552,7 +552,7 @@ Computes the singular value decomposition `A = USVh` of a matrix (or a stack of #### Returns -- **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ +- **out**: _Tuple\[ <array>, <array>, <array> ]_ - a namedtuple `(u, s, vh)` whose @@ -562,11 +562,6 @@ Computes the singular value decomposition `A = USVh` of a matrix (or a stack of Each returned array must have the same floating-point data type as `x`. -(function-linalg-tensordot)= -### linalg.tensordot(x1, x2, /, *, axes=2) - -Alias for {ref}`function-tensordot`. - (function-linalg-svdvals)= ### linalg.svdvals(x, /) @@ -584,6 +579,11 @@ Computes the singular values of a matrix (or a stack of matrices) `x`. - an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. The returned array must have the same floating-point data type as `x`. +(function-linalg-tensordot)= +### linalg.tensordot(x1, x2, /, *, axes=2) + +Alias for {ref}`function-tensordot`. + (function-linalg-trace)= ### linalg.trace(x, /, *, offset=0) From e672ef3ee64e06a4eb4f9c17483f7eb144e4c83e Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 23 Aug 2021 09:46:43 -0500 Subject: [PATCH 039/551] Run preview action only in the main repository --- .github/workflows/preview.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 46e9a1ef9..b4d2b05b4 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -1,6 +1,7 @@ on: [status] jobs: circleci_artifacts_redirector_job: + if: ${{ github.repository_owner == 'data-apis' }} runs-on: ubuntu-latest name: Run CircleCI artifacts redirector steps: @@ -14,4 +15,4 @@ jobs: job-title: Check the rendered docs here! - name: Array API preview run: | - curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA \ No newline at end of file + curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA From 9418c9da9a0a10ec1d16488b0d29e8f579998c9b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 23 Aug 2021 09:49:45 -0500 Subject: [PATCH 040/551] Add skip CI to preview action --- .github/workflows/preview.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index b4d2b05b4..e57005e1e 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -1,7 +1,8 @@ on: [status] jobs: circleci_artifacts_redirector_job: - if: ${{ github.repository_owner == 'data-apis' }} + # Don't run Action on forks, and allow skipping CI + if: "github.repository == 'data-apis/array-api' && !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip github]')" runs-on: ubuntu-latest name: Run CircleCI artifacts redirector steps: From 4c76abdeaa8064795e47e4e712ab52d0e9b8d9b7 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 23 Aug 2021 09:54:14 -0500 Subject: [PATCH 041/551] Test commit From 3d81da4e7197a0515012e70f498b64b59055cca7 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 23 Aug 2021 09:58:09 -0500 Subject: [PATCH 042/551] Run action only in the main repo --- .github/workflows/preview.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index e57005e1e..cdb310fe4 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -2,7 +2,7 @@ on: [status] jobs: circleci_artifacts_redirector_job: # Don't run Action on forks, and allow skipping CI - if: "github.repository == 'data-apis/array-api' && !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip github]')" + if: "github.repository == 'data-apis/array-api'" runs-on: ubuntu-latest name: Run CircleCI artifacts redirector steps: From 300227985196ef4764bba12a7db94741ce9e3aa2 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 23 Aug 2021 11:11:59 -0700 Subject: [PATCH 043/551] Remove linalg.lstsq (#240) --- spec/extensions/linear_algebra_functions.md | 30 --------------------- 1 file changed, 30 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index b2f59082b..2155d198c 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -259,36 +259,6 @@ Computes the multiplicative inverse of a square matrix (or a stack of square mat - an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have the same shape as `x`. -(function-linalg-lstsq)= -### linalg.lstsq(x1, x2, /, *, rtol=None) - -Returns the least-squares solution to a linear matrix equation `Ax = b`. - -#### Parameters - -- **x1**: _<array>_ - - - coefficient array `A` having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - -- **x2**: _<array>_ - - - ordinate (or "dependent variable") array `b`. If `x2` has shape `(..., M)`, `x2` is equivalent to an array having shape `(..., M, 1)`, and `shape(x2)` must be compatible with `shape(x1)[:-1]` (see {ref}`broadcasting`). If `x2` has shape `(..., M, K)`, each column `k` defines a set of ordinate values for which to compute a solution, and `shape(x2)[:-1]` must be compatible with `shape(x1)[:-1]` (see {ref}`broadcasting`). Should have a floating-point data type. - -- **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - - relative tolerance for small singular values. Singular values less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a data type determined by {ref}`type-promotion` (as applied to `x1` and `x2`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x1)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x1` and `x2`). Default: `None`. - -#### Returns - -- **out**: _Tuple\[ <array>, <array>, <array>, <array> ]_ - - - a namedtuple `(x, residuals, rank, s)` whose - - - first element must have the field name `x` and must be an array containing the least-squares solution for each `MxN` matrix in `x1`. The array containing the solutions must have shape `(N, K)` and must have a floating-point data type determined by {ref}`type-promotion`. - - second element must have the field name `residuals` and must be an array containing the sum of squares residuals (i.e., the squared Euclidean 2-norm for each column in `b - Ax`). The array containing the residuals must have shape `(K,)` and must have a floating-point data type determined by {ref}`type-promotion`. - - third element must have the field name `rank` and must be an array containing the effective rank of each `MxN` matrix. The array containing the ranks must have shape `shape(x1)[:-2]` and must have an integer data type. - - fourth element must have the field name `s` and must be an array containing the singular values for each `MxN` matrix in `x1`. The array containing the singular values must have shape `(..., min(M, N))` and must have a floating-point data type determined by {ref}`type-promotion`. - (function-linalg-matmul)= ### linalg.matmul(x1, x2, /) From a7a91fea22007c0c211ccbaa09a10c710e694620 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 23 Aug 2021 11:18:34 -0700 Subject: [PATCH 044/551] Split `linalg.norm` into separate vector and matrix APIs (#236) --- spec/extensions/linear_algebra_functions.md | 163 +++++++++++--------- 1 file changed, 92 insertions(+), 71 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 2155d198c..2e4302539 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -264,123 +264,98 @@ Computes the multiplicative inverse of a square matrix (or a stack of square mat Alias for {ref}`function-matmul`. -(function-linalg-matrix_power)= -### linalg.matrix_power(x, n, /) +(function-linalg-matrix-norm)= +### linalg.matrix_norm(x, /, *, axis=(-2, -1), keepdims=False, ord='fro') -Raises a square matrix (or a stack of square matrices) `x` to an integer power `n`. +Computes the matrix norm of a matrix (or a stack of matrices) `x`. #### Parameters - **x**: _<array>_ - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + - input array. Must have at least `2` dimensions. Should have a floating-point data type. -- **n**: _int_ +- **axis**: _Tuple\[ int, int ]_ - - integer exponent. + - a 2-tuple which specifies the axes (dimensions) defining two-dimensional matrices for which to compute matrix norms. Negative indices must be supported. Default: `(-2, -1)` (i.e., the last two-dimensions). -#### Returns +- **keepdims**: _bool_ -- **out**: _<array>_ + - If `True`, the axes (dimensions) specified by `axis` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the axes (dimensions) specified by `axis` must not be included in the result. Default: `False`. - - if `n` is equal to zero, an array containing the identity matrix for each square matrix. If `n` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of `n`, provided that each square matrix is invertible. If `n` is greater than zero, an array containing the result of raising each square matrix to the power `n`. The returned array must have the same shape as `x` and a floating-point data type determined by {ref}`type-promotion`. +- **ord**: _Optional\[ Union\[ int, float, Literal\[ inf, -inf, 'fro', 'nuc' ] ] ]_ -(function-linalg-matrix_rank)= -### linalg.matrix_rank(x, /, *, rtol=None) + - order of the norm. The following mathematical norms must be supported: + | ord | description | + | ---------------- | ------------------------------- | + | 'fro' | Frobenius norm | + | 'nuc' | nuclear norm | + | 1 | max(sum(abs(x), axis=0)) | + | 2 | largest singular value | + | inf | max(sum(abs(x), axis=1)) | -Computes the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). + The following non-mathematical "norms" must be supported: + | ord | description | + | ---------------- | ------------------------------- | + | -1 | min(sum(abs(x), axis=0)) | + | -2 | smallest singular value | + | -inf | min(sum(abs(x), axis=1)) | -#### Parameters + If `ord=1`, the norm corresponds to the induced matrix norm where `p=1` (i.e., the maximum absolute value column sum). -- **x**: _<array>_ + If `ord=2`, the norm corresponds to the induced matrix norm where `p=inf` (i.e., the maximum absolute value row sum). - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. + If `ord=inf`, the norm corresponds to the induced matrix norm where `p=2` (i.e., the largest singular value). -- **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - - relative tolerance for small singular values. Singular values less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. + Default: `'fro'`. #### Returns - **out**: _<array>_ - - an array containing the ranks. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have shape `(...)` (i.e., must have a shape equal to `shape(x)[:-2]`). + - an array containing the norms. If `keepdims` is `False`, the returned array must have a rank which is two less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. -(function-linalg-norm)= -### linalg.norm(x, /, *, axis=None, keepdims=False, ord=None) +(function-linalg-matrix_power)= +### linalg.matrix_power(x, n, /) -Computes the matrix or vector norm of `x`. +Raises a square matrix (or a stack of square matrices) `x` to an integer power `n`. #### Parameters - **x**: _<array>_ - - input array. Should have a floating-point data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, int ] ] ]_ - - - If an integer, `axis` specifies the axis (dimension) along which to compute vector norms. - - If a 2-tuple, `axis` specifies the axes (dimensions) defining two-dimensional matrices for which to compute matrix norms. - - If `None`, - - - if `x` is one-dimensional, the function must compute the vector norm. - - if `x` is two-dimensional, the function must compute the matrix norm. - - if `x` has more than two dimensions, the function must compute the vector norm over all array values (i.e., equivalent to computing the vector norm of a flattened array). - - Negative indices must be supported. Default: `None`. + - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. -- **keepdims**: _bool_ +- **n**: _int_ - - If `True`, the axes (dimensions) specified by `axis` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the axes (dimensions) specified by `axis` must not be included in the result. Default: `False`. + - integer exponent. -- **ord**: _Optional\[ Union\[ int, float, Literal\[ inf, -inf, 'fro', 'nuc' ] ] ]_ +#### Returns - - order of the norm. The following mathematical norms must be supported: - | ord | matrix | vector | - | ---------------- | ------------------------------- | -------------------------- | - | 'fro' | 'fro' | - | - | 'nuc' | 'nuc' | - | - | 1 | max(sum(abs(x), axis=0)) | L1-norm (Manhattan) | - | 2 | largest singular value | L2-norm (Euclidean) | - | inf | max(sum(abs(x), axis=1)) | infinity norm | - | (int,float >= 1) | - | p-norm | +- **out**: _<array>_ - The following non-mathematical "norms" must be supported: - | ord | matrix | vector | - | ---------------- | ------------------------------- | ------------------------------ | - | 0 | - | sum(a != 0) | - | -1 | min(sum(abs(x), axis=0)) | 1./sum(1./abs(a)) | - | -2 | smallest singular value | 1./sqrt(sum(1./abs(a)\*\*2)) | - | -inf | min(sum(abs(x), axis=1)) | min(abs(a)) | - | (int,float < 1) | - | sum(abs(a)\*\*ord)\*\*(1./ord) | + - if `n` is equal to zero, an array containing the identity matrix for each square matrix. If `n` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of `n`, provided that each square matrix is invertible. If `n` is greater than zero, an array containing the result of raising each square matrix to the power `n`. The returned array must have the same shape as `x` and a floating-point data type determined by {ref}`type-promotion`. - When `ord` is `None`, the following norms must be the default norms: - | ord | matrix | vector | - | ---------------- | ------------------------------- | -------------------------- | - | None | 'fro' | L2-norm (Euclidean) | +(function-linalg-matrix_rank)= +### linalg.matrix_rank(x, /, *, rtol=None) - where `fro` corresponds to the **Frobenius norm**, `nuc` corresponds to the **nuclear norm**, and `-` indicates that the norm is **not** supported. +Computes the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). - For matrices, +#### Parameters - - if `ord=1`, the norm corresponds to the induced matrix norm where `p=1` (i.e., the maximum absolute value column sum). - - if `ord=2`, the norm corresponds to the induced matrix norm where `p=inf` (i.e., the maximum absolute value row sum). - - if `ord=inf`, the norm corresponds to the induced matrix norm where `p=2` (i.e., the largest singular value). +- **x**: _<array>_ - If `None`, + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - - if matrix (or matrices), the function must compute the Frobenius norm. - - if vector (or vectors), the function must compute the L2-norm (Euclidean norm). +- **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - Default: `None`. + - relative tolerance for small singular values. Singular values less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. #### Returns - **out**: _<array>_ - - an array containing the norms. If `axis` is `None`, the returned array must be a zero-dimensional array containing a vector norm. If `axis` is a scalar value (`int` or `float`), the returned array must have a rank which is one less than the rank of `x`. If `axis` is a 2-tuple, the returned array must have a rank which is two less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. + - an array containing the ranks. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have shape `(...)` (i.e., must have a shape equal to `shape(x)[:-2]`). (function-linalg-outer)= ### linalg.outer(x1, x2, /) @@ -596,3 +571,49 @@ Alias for {ref}`function-transpose`. ### linalg.vecdot(x1, x2, /, *, axis=None) Alias for {ref}`function-vecdot`. + +(function-linalg-vector-norm)= +### linalg.vector_norm(x, /, *, axis=None, keepdims=False, ord=2) + +Computes the vector norm of a vector (or batch of vectors) `x`. + +#### Parameters + +- **x**: _<array>_ + + - input array. Should have a floating-point data type. + +- **axis**: _Optional\[ Union\[ int, Tuple\[ int, int ] ] ]_ + + - If an integer, `axis` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, `axis` specifies the axes (dimensions) along which to compute batched vector norms. If `None`, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: `None`. + +- **keepdims**: _bool_ + + - If `True`, the axes (dimensions) specified by `axis` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the axes (dimensions) specified by `axis` must not be included in the result. Default: `False`. + +- **ord**: _Optional\[ Union\[ int, float, Literal\[ inf, -inf ] ] ]_ + + - order of the norm. The following mathematical norms must be supported: + | ord | description | + | ---------------- | -------------------------- | + | 1 | L1-norm (Manhattan) | + | 2 | L2-norm (Euclidean) | + | inf | infinity norm | + | (int,float >= 1) | p-norm | + + The following non-mathematical "norms" must be supported: + | ord | description | + | ---------------- | ------------------------------ | + | 0 | sum(a != 0) | + | -1 | 1./sum(1./abs(a)) | + | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | + | -inf | min(abs(a)) | + | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | + + Default: `2`. + +#### Returns + +- **out**: _<array>_ + + - an array containing the vector norms. If `axis` is `None`, the returned array must be a zero-dimensional array containing a vector norm. If `axis` is a scalar value (`int` or `float`), the returned array must have a rank which is one less than the rank of `x`. If `axis` is a `n`-tuple, the returned array must have a rank which is `n` less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. From 8232c5f5b8e52ba645a370958cffc45d2403153a Mon Sep 17 00:00:00 2001 From: soraros Date: Fri, 10 Sep 2021 18:30:25 +0200 Subject: [PATCH 045/551] Fix wrong function name in array_object.py (#258) --- spec/API_specification/array_object.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index dcf78228b..7d9640715 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -953,7 +953,7 @@ Evaluates `self_i | other_i` for each element of an array instance with the resp ```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`positive(x1, x2)`](elementwise_functions.md#bitwise_orx1-x2-). +Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_or(x1, x2)`](elementwise_functions.md#bitwise_orx1-x2-). ``` (method-__pos__)= From b1340735b8be3701dd6fe958674412ba3b8b3efd Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 13 Sep 2021 02:18:38 -0600 Subject: [PATCH 046/551] Specify input dtypes for the statistical functions (#234) Functions like mean() that perform divisions require floating-point inputs. All other functions require numeric inputs. --- spec/API_specification/statistical_functions.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md index 1f5c6f2ab..39ea18280 100644 --- a/spec/API_specification/statistical_functions.md +++ b/spec/API_specification/statistical_functions.md @@ -24,7 +24,7 @@ Calculates the maximum value of the input array `x`. - **x**: _<array>_ - - input array. + - input array. Should have a numeric data type. - **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ @@ -49,7 +49,7 @@ Calculates the arithmetic mean of the input array `x`. - **x**: _<array>_ - - input array. + - input array. Should have a floating-point data type. - **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ @@ -74,7 +74,7 @@ Calculates the minimum value of the input array `x`. - **x**: _<array>_ - - input array. + - input array. Should have a numeric data type. - **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ @@ -99,7 +99,7 @@ Calculates the product of input array `x` elements. - **x**: _<array>_ - - input array. + - input array. Should have a numeric data type. - **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ @@ -124,7 +124,7 @@ Calculates the standard deviation of the input array `x`. - **x**: _<array>_ - - input array. + - input array. Should have a floating-point data type. - **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ @@ -153,7 +153,7 @@ Calculates the sum of the input array `x`. - **x**: _<array>_ - - input array. + - input array. Should have a numeric data type. - **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ @@ -178,7 +178,7 @@ Calculates the variance of the input array `x`. - **x**: _<array>_ - - input array. + - input array. Should have a floating-point data type. - **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ From 8009f8b73c47410821c56eda3670dd15acf92671 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 13 Sep 2021 01:57:06 -0700 Subject: [PATCH 047/551] Restrict the `T` attribute to two-dimensional arrays (#245) * Restrict the `T` attribute to two-dimensional arrays * Add API recommendation * Fix function name --- spec/API_specification/array_object.md | 36 +++++--------------------- 1 file changed, 7 insertions(+), 29 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 7d9640715..a3d8aeba7 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -183,7 +183,6 @@ an array object supporting the following reflected operators: The results of applying reflected operators must match their non-reflected equivalents. ```{note} - All operators for which `array scalar` is implemented must have an equivalent reflected operator implementation. ``` @@ -259,11 +258,17 @@ _TODO: need to more carefully consider this in order to accommodate, e.g., graph Transpose of the array. +The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. + +```{note} +Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional `permute` interface found in this specification. +``` + #### Returns - **out**: _<array>_ - - array whose dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. + - two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. * * * @@ -297,7 +302,6 @@ For floating-point operands, let `self` equal `x`. - an array containing the element-wise absolute value. The returned array must have the same data type as `self`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`abs(x)`](elementwise_functions.md#absx-). ``` @@ -329,7 +333,6 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - In the remaining cases, when neither `infinity`, `+0`, `-0`, nor a `NaN` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. ```{note} - Floating-point addition is a commutative operation, but not always associative. ``` @@ -350,7 +353,6 @@ Floating-point addition is a commutative operation, but not always associative. - an array containing the element-wise sums. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`add(x1, x2)`](elementwise_functions.md#addx1-x2-). ``` @@ -376,7 +378,6 @@ Evaluates `self_i & other_i` for each element of an array instance with the resp - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_and(x1, x2)`](elementwise_functions.md#logical_andx1-x2-). ``` @@ -524,7 +525,6 @@ Computes the truth value of `self_i == other_i` for each element of an array ins - an array containing the element-wise results. The returned array must have a data type of `bool`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`equal(x1, x2)`](elementwise_functions.md#equalx1-x2-). ``` @@ -567,7 +567,6 @@ Evaluates `self_i // other_i` for each element of an array instance with the res - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`floor_divide(x1, x2)`](elementwise_functions.md#floor_dividex1-x2-). ``` @@ -593,7 +592,6 @@ Computes the truth value of `self_i >= other_i` for each element of an array ins - an array containing the element-wise results. The returned array must have a data type of `bool`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`greater_equal(x1, x2)`](elementwise_functions.md#greater_equalx1-x2-). ``` @@ -640,7 +638,6 @@ Computes the truth value of `self_i > other_i` for each element of an array inst - an array containing the element-wise results. The returned array must have a data type of `bool`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`greater(x1, x2)`](elementwise_functions.md#greaterx1-x2-). ``` @@ -679,7 +676,6 @@ Evaluates `~self_i` for each element of an array instance. - an array containing the element-wise results. The returned array must have the same data type as `self`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_invert(x)`](elementwise_functions.md#bitwise_invertx-). ``` @@ -705,7 +701,6 @@ Computes the truth value of `self_i <= other_i` for each element of an array ins - an array containing the element-wise results. The returned array must have a data type of `bool`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`less_equal(x1, x2)`](elementwise_functions.md#less_equalx1-x2-). ``` @@ -736,7 +731,6 @@ Evaluates `self_i << other_i` for each element of an array instance with the res - an array containing the element-wise results. The returned array must have the same data type as `self`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_left_shift(x1, x2)`](elementwise_functions.md#bitwise_left_shiftx1-x2-). ``` @@ -762,7 +756,6 @@ Computes the truth value of `self_i < other_i` for each element of an array inst - an array containing the element-wise results. The returned array must have a data type of `bool`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`less(x1, x2)`](elementwise_functions.md#lessx1-x2-). ``` @@ -772,7 +765,6 @@ Element-wise results must equal the results returned by the equivalent element-w Computes the matrix product. ```{note} - The `matmul` function must implement the same semantics as the built-in `@` operator (see [PEP 465](https://www.python.org/dev/peps/pep-0465)). ``` @@ -801,7 +793,6 @@ The `matmul` function must implement the same semantics as the built-in `@` oper The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Results must equal the results returned by the equivalent function [`matmul(x1, x2)`](linear_algebra_functions.md#matmulx1-x2-). ``` @@ -833,7 +824,6 @@ Evaluates `self_i % other_i` for each element of an array instance with the resp - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element `other_i`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`remainder(x1, x2)`](elementwise_functions.md#remainderx1-x2-). ``` @@ -857,7 +847,6 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - In the remaining cases, where neither `infinity` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. ```{note} - Floating-point multiplication is not always associative due to finite precision. ``` @@ -878,7 +867,6 @@ Floating-point multiplication is not always associative due to finite precision. - an array containing the element-wise products. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`multiply(x1, x2)`](elementwise_functions.md#multiplyx1-x2-). ``` @@ -904,7 +892,6 @@ Computes the truth value of `self_i != other_i` for each element of an array ins - an array containing the element-wise results. The returned array must have a data type of `bool` (i.e., must be a boolean array). ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`not_equal(x1, x2)`](elementwise_functions.md#not_equalx1-x2-). ``` @@ -926,7 +913,6 @@ Evaluates `-self_i` for each element of an array instance. - an array containing the evaluated result for each element in `self`. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`negative(x)`](elementwise_functions.md#negativex-). ``` @@ -952,7 +938,6 @@ Evaluates `self_i | other_i` for each element of an array instance with the resp - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_or(x1, x2)`](elementwise_functions.md#bitwise_orx1-x2-). ``` @@ -974,7 +959,6 @@ Evaluates `+self_i` for each element of an array instance. - an array containing the evaluated result for each element. The returned array must have the same data type as `self`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`positive(x)`](elementwise_functions.md#positivex-). ``` @@ -1029,7 +1013,6 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`pow(x1, x2)`](elementwise_functions.md#powx1-x2-). ``` @@ -1055,7 +1038,6 @@ Evaluates `self_i >> other_i` for each element of an array instance with the res - an array containing the element-wise results. The returned array must have the same data type as `self`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_right_shift(x1, x2)`](elementwise_functions.md#bitwise_right_shiftx1-x2-). ``` @@ -1079,7 +1061,6 @@ Sets `self[key]` to `value`. - value(s) to set. Must be compatible with `self[key]` (see {ref}`broadcasting`). ```{note} - Setting array values must not affect the data type of `self`. When `value` is a Python scalar (i.e., `int`, `float`, `bool`), behavior must follow specification guidance on mixing arrays with Python scalars (see {ref}`type-promotion`). @@ -1109,7 +1090,6 @@ Calculates the difference for each element of an array instance with the respect - an array containing the element-wise differences. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`subtract(x1, x2)`](elementwise_functions.md#subtractx1-x2-). ``` @@ -1162,7 +1142,6 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`divide(x1, x2)`](elementwise_functions.md#dividex1-x2-). ``` @@ -1188,6 +1167,5 @@ Evaluates `self_i ^ other_i` for each element of an array instance with the resp - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. ```{note} - Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_xor(x1, x2)`](elementwise_functions.md#bitwise_xorx1-x2-). ``` From 527ec4f653addfba22c18e7689f2d027f3e4b996 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 13 Sep 2021 02:21:30 -0700 Subject: [PATCH 048/551] Add specification for computing the matrix transpose (#248) --- .../linear_algebra_functions.md | 38 +++++++++---------- spec/extensions/linear_algebra_functions.md | 10 ++--- 2 files changed, 22 insertions(+), 26 deletions(-) diff --git a/spec/API_specification/linear_algebra_functions.md b/spec/API_specification/linear_algebra_functions.md index 3724c2c24..fb8b0f4ec 100644 --- a/spec/API_specification/linear_algebra_functions.md +++ b/spec/API_specification/linear_algebra_functions.md @@ -60,6 +60,23 @@ The `matmul` function must implement the same semantics as the built-in `@` oper - if `x1` is a one-dimensional array having shape `(N)`, `x2` is a one-dimensional array having shape `(M)`, and `N != M`. - if `x1` is an array having shape `(..., M, K)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. +(function-matrix-transpose)= +### matrix_transpose(x, /) + +Transposes a matrix (or a stack of matrices) `x`. + +#### Parameters + +- **x**: _<array>_ + + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. + +#### Returns + +- **out**: _<array>_ + + - an array containing the transpose for each matrix and having shape `(..., N, M)`. The returned array must have the same data type as `x`. + (function-tensordot)= ### tensordot(x1, x2, /, *, axes=2) @@ -93,27 +110,6 @@ Returns a tensor contraction of `x1` and `x2` over specific axes. - an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array `x1`, followed by the non-contracted axes (dimensions) of the second array `x2`. The returned array must have a data type determined by {ref}`type-promotion`. -(function-transpose)= -### transpose(x, /, *, axes=None) - -Transposes (or permutes the axes (dimensions)) of an array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axes**: _Optional\[ Tuple\[ int, ... ] ]_ - - - tuple containing a permutation of `(0, 1, ..., N-1)` where `N` is the number of axes (dimensions) of `x`. If `None`, the axes (dimensions) must be permuted in reverse order (i.e., equivalent to setting `axes=(N-1, ..., 1, 0)`). Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the transpose. The returned array must have the same data type as `x`. - (function-vecdot)= ### vecdot(x1, x2, /, *, axis=None) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 2e4302539..a069d6a03 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -357,6 +357,11 @@ Computes the rank (i.e., number of non-zero singular values) of a matrix (or a s - an array containing the ranks. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have shape `(...)` (i.e., must have a shape equal to `shape(x)[:-2]`). +(function-linalg-matrix-transpose)= +### linalg.matrix_transpose(x, /) + +Alias for {ref}`function-matrix-transpose`. + (function-linalg-outer)= ### linalg.outer(x1, x2, /) @@ -562,11 +567,6 @@ Returns the sum along the specified diagonals of a matrix (or a stack of matrice The returned array must have the same data type as `x`. -(function-linalg-transpose)= -### linalg.transpose(x, /, *, axes=None) - -Alias for {ref}`function-transpose`. - (function-linalg-vecdot)= ### linalg.vecdot(x1, x2, /, *, axis=None) From 38bbea70efc946ce4595134c05b6391f5937a11e Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 13 Sep 2021 02:30:43 -0700 Subject: [PATCH 049/551] Add specification for `.mT` attribute (#246) --- spec/API_specification/array_object.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index a3d8aeba7..b1c120311 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -214,6 +214,19 @@ Hardware device the array data resides on. - a `device` object (see {ref}`device-support`). +(attribute-mT)= +### mT + +Transpose of a matrix (or a stack of matrices). + +If an array instance has fewer than two dimensions, an error should be raised. + +#### Returns + +- **out**: _<array>_ + + - array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape `(..., M, N)`, the returned array must have shape `(..., N, M)`). The returned array must have the same data type as the original array. + (attribute-ndim)= ### ndim From fa99036a12b74719841ebc5ad46a791bdedd566b Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 13 Sep 2021 04:21:08 -0600 Subject: [PATCH 050/551] Clarify guidance regarding non-boolean input array dtypes in the logical_* functions (#251) * Clarify some text in the logical_* functions Only boolean data types are required in these functions, so the zero-nonzero bool equivalence is only for implementations that choose to implement non-boolean inputs. * Move clarifications to notes Co-authored-by: Athan --- .../elementwise_functions.md | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 97c77c6bc..53658af0a 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -968,7 +968,11 @@ For floating-point operands, (function-logical_and)= ### logical_and(x1, x2, /) -Computes the logical AND for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. Zeros are considered the equivalent of `False`, while non-zeros are considered the equivalent of `True`. +Computes the logical AND for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. + +```{note} +While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. +``` #### Parameters @@ -989,7 +993,11 @@ Computes the logical AND for each element `x1_i` of the input array `x1` with th (function-logical_not)= ### logical_not(x, /) -Computes the logical NOT for each element `x_i` of the input array `x`. Zeros are considered the equivalent of `False`, while non-zeros are considered the equivalent of `True`. +Computes the logical NOT for each element `x_i` of the input array `x`. + +```{note} +While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. +``` #### Parameters @@ -1006,7 +1014,11 @@ Computes the logical NOT for each element `x_i` of the input array `x`. Zeros ar (function-logical_or)= ### logical_or(x1, x2, /) -Computes the logical OR for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. Zeros are considered the equivalent of `False`, while non-zeros are considered the equivalent of `True`. +Computes the logical OR for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. + +```{note} +While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. +``` #### Parameters @@ -1027,7 +1039,11 @@ Computes the logical OR for each element `x1_i` of the input array `x1` with the (function-logical_xor)= ### logical_xor(x1, x2, /) -Computes the logical XOR for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. Zeros are considered the equivalent of `False`, while non-zeros are considered the equivalent of `True`. +Computes the logical XOR for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. + +```{note} +While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. +``` #### Parameters From 378255cb80163d3b6cf211f67997e7ad98d96f38 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 13 Sep 2021 04:27:55 -0600 Subject: [PATCH 051/551] Fix error in remainder (#253) It stated that the return type should be floating-point, but it accepts integer inputs (and the remainder of two integers is always an integer). --- spec/API_specification/elementwise_functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 53658af0a..570119540 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -1225,7 +1225,7 @@ Returns the remainder of division for each element `x1_i` of the input array `x1 - **out**: _<array>_ - - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element `x2_i`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. + - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element `x2_i`. The returned array must have a data type determined by {ref}`type-promotion`. (function-round)= ### round(x, /) From 85d317049bf13fbf94f343ec2db046a32445dc2a Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 14 Sep 2021 09:34:01 -0700 Subject: [PATCH 052/551] Clarify output dtype guidance for `mean`, `var`, and `std` (#260) --- .../API_specification/statistical_functions.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md index 39ea18280..eb4346c3e 100644 --- a/spec/API_specification/statistical_functions.md +++ b/spec/API_specification/statistical_functions.md @@ -63,7 +63,11 @@ Calculates the arithmetic mean of the input array `x`. - **out**: _<array>_ - - if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have be the default floating-point data type. + - if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as `x`. + + ```{note} + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array `x` has an integer data type, the returned array must have the default floating-point data type. + ``` (function-min)= ### min(x, /, *, axis=None, keepdims=False) @@ -142,7 +146,11 @@ Calculates the standard deviation of the input array `x`. - **out**: _<array>_ - - if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the default floating-point data type. + - if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as `x`. + + ```{note} + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array `x` has an integer data type, the returned array must have the default floating-point data type. + ``` (function-sum)= ### sum(x, /, *, axis=None, keepdims=False) @@ -196,4 +204,8 @@ Calculates the variance of the input array `x`. - **out**: _<array>_ - - if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the default floating-point data type. + - if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the same data type as `x`. + + ```{note} + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array `x` has an integer data type, the returned array must have the default floating-point data type. + ``` From 5e33e0d5210d1d01ab8d24c14cba8810fbd522ed Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 14 Sep 2021 09:38:37 -0700 Subject: [PATCH 053/551] Add `__index__` to array object (#263) --- spec/API_specification/array_object.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 54d6419b0..0b0ca24f1 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -654,6 +654,27 @@ Computes the truth value of `self_i > other_i` for each element of an array inst Element-wise results must equal the results returned by the equivalent element-wise function [`greater(x1, x2)`](elementwise_functions.md#greaterx1-x2-). ``` +(method-__index__)= +### \_\_index\_\_(self, /) + +Converts a zero-dimensional integer array to a Python `int` object. + +```{note} +This method is called to implement [`operator.index()`](https://docs.python.org/3/reference/datamodel.html#object.__index__). See also [PEP 357](https://www.python.org/dev/peps/pep-0357/). +``` + +#### Parameters + +- **self**: _<array>_ + + - zero-dimensional array instance. Must have an integer data type. + +#### Returns + +- **out**: _<int>_ + + - a Python `int` object representing the single element of the array instance. + (method-__int__)= ### \_\_int\_\_(self, /) From 7499649be5041b9cc74c29d859da7a0c7bedeeec Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 15 Sep 2021 07:58:47 -0700 Subject: [PATCH 054/551] Add a note clarifying edge case (#261) --- spec/API_specification/creation_functions.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index da7b250b4..b482c6d06 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -206,7 +206,11 @@ Returns a new array having a specified `shape` and filled with `fill_value`. - **dtype**: _Optional\[ <dtype> ]_ - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `fill_value`. If it's an `int`, the output array dtype must be the default integer dtype; if it's a `float`, then the output array dtype must be the default floating-point data type; if it's a `bool` then the output array must have boolean dtype. Default: `None`. + - output array data type. If `dtype` is `None`, the output array data type must be inferred from `fill_value`. If the fill value is an `int`, the output array data type must be the default integer data type. If the fill value is a `float`, the output array data type must be the default floating-point data type. If the fill value is a `bool`, the output array must have boolean data type. Default: `None`. + + ```{note} + If `dtype` is `None` and the `fill_value` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + ``` - **device**: _Optional\[ <device> ]_ @@ -237,6 +241,10 @@ Returns a new array filled with `fill_value` and having the same `shape` as an i - output array data type. If `dtype` is `None`, the output array data type must be inferred from `fill_value` (see {ref}`function-full`). Default: `None`. + ```{note} + If `dtype` is `None` and the `fill_value` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + ``` + - **device**: _Optional\[ <device> ]_ - device to place the created array on, if given. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. From 85d6b31c4097f988498d3453d7940bada48e0c58 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 15 Sep 2021 08:00:31 -0700 Subject: [PATCH 055/551] Specify behavior of statistical reductions over the empty set (#262) * Specify `mean` behavior when provided a 0D array * Specify `prod` behavior when provided a 0D array * Specify `sum` behavior when provided a 0D array * Rephrase special cases and add special cases for other stats reductions * Add guidance for min and max when `x` is 0D --- .../statistical_functions.md | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md index eb4346c3e..97174ce1d 100644 --- a/spec/API_specification/statistical_functions.md +++ b/spec/API_specification/statistical_functions.md @@ -20,6 +20,10 @@ A conforming implementation of the array API standard must provide and support t Calculates the maximum value of the input array `x`. +```{note} +When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the minimum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `-infinity`). +``` + #### Parameters - **x**: _<array>_ @@ -45,6 +49,12 @@ Calculates the maximum value of the input array `x`. Calculates the arithmetic mean of the input array `x`. +#### Special Cases + +For a floating-point input array `x`, let `N` equal the number of elements over which to compute the arithmetic mean and + +- if `N` is `0`, the arithmetic mean is `NaN`. + #### Parameters - **x**: _<array>_ @@ -74,6 +84,10 @@ Calculates the arithmetic mean of the input array `x`. Calculates the minimum value of the input array `x`. +```{note} +When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the maximum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `+infinity`). +``` + #### Parameters - **x**: _<array>_ @@ -99,6 +113,12 @@ Calculates the minimum value of the input array `x`. Calculates the product of input array `x` elements. +#### Special Cases + +For an input array `x`, let `N` equal the number of elements over which to compute the product and + +- if `N` is `0`, the product is `1` (i.e., the empty product). + #### Parameters - **x**: _<array>_ @@ -124,6 +144,12 @@ Calculates the product of input array `x` elements. Calculates the standard deviation of the input array `x`. +#### Special Cases + +For a floating-point input array `x`, let `N` equal the number of elements over which to compute the standard deviation and + +- if `N - correction` is less than or equal to `0`, the standard deviation is `NaN`. + #### Parameters - **x**: _<array>_ @@ -157,6 +183,12 @@ Calculates the standard deviation of the input array `x`. Calculates the sum of the input array `x`. +#### Special Cases + +For an input array `x`, let `N` equal the number of elements over which to compute the sum and + +- if `N` is `0`, the sum is `0` (i.e., the empty sum). + #### Parameters - **x**: _<array>_ @@ -182,6 +214,12 @@ Calculates the sum of the input array `x`. Calculates the variance of the input array `x`. +#### Special Cases + +For a floating-point input array `x`, let `N` equal the number of elements over which to compute the variance and + +- if `N - correction` is less than or equal to `0`, the variance is `NaN`. + #### Parameters - **x**: _<array>_ From 25e24ca2c8a362067268c59a02eb625ff60883f4 Mon Sep 17 00:00:00 2001 From: Athan Date: Fri, 17 Sep 2021 16:14:49 -0700 Subject: [PATCH 056/551] Add `dtype` keyword argument to `sum` and `prod` (#238) * Add `dtype` keyword to `sum` and `prod` * Update copy * Fix copy * Remove empty lines Co-authored-by: Leo Fang * Remove duplicate word Co-authored-by: Leo Fang * Remove empty lines * Fix promotion rules for sum and prod * Update desc Co-authored-by: Aaron Meurer * Update desc * Clarify casting rules Co-authored-by: Leo Fang Co-authored-by: Aaron Meurer --- .../statistical_functions.md | 34 ++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md index 97174ce1d..debccc185 100644 --- a/spec/API_specification/statistical_functions.md +++ b/spec/API_specification/statistical_functions.md @@ -109,7 +109,7 @@ When the number of elements over which to compute the minimum value is zero, the - if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as `x`. (function-prod)= -### prod(x, /, *, axis=None, keepdims=False) +### prod(x, /, *, axis=None, dtype=None, keepdims=False) Calculates the product of input array `x` elements. @@ -129,6 +129,19 @@ For an input array `x`, let `N` equal the number of elements over which to compu - axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: `None`. +- **dtype**: _Optional\[ <dtype> ]_ + + - data type of the returned array. If `None`, + + - if the default data type corresponding to the data type "kind" (integer or floating-point) of `x` has a smaller range of values than the data type of `x` (e.g., `x` has data type `int64` and the default data type is `int32`, or `x` has data type `uint64` and the default data type is `int64`), the returned array must have the same data type as `x`. + - otherwise, the returned array must have the default data type corresponding to the data type "kind" (integer or floating-point) of `x`. + + If the data type (either specified or resolved) differs from the data type of `x`, the input array should be cast to the specified data type before computing the product. Default: `None`. + + ```{note} + This keyword argument is intended to help prevent data type overflows. + ``` + - **keepdims**: _bool_ - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. @@ -137,7 +150,7 @@ For an input array `x`, let `N` equal the number of elements over which to compu - **out**: _<array>_ - - if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have the same data type as `x`. + - if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the `dtype` parameter above. (function-std)= ### std(x, /, *, axis=None, correction=0.0, keepdims=False) @@ -179,7 +192,7 @@ For a floating-point input array `x`, let `N` equal the number of elements over ``` (function-sum)= -### sum(x, /, *, axis=None, keepdims=False) +### sum(x, /, *, axis=None, dtype=None, keepdims=False) Calculates the sum of the input array `x`. @@ -199,6 +212,19 @@ For an input array `x`, let `N` equal the number of elements over which to compu - axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: `None`. +- **dtype**: _Optional\[ <dtype> ]_ + + - data type of the returned array. If `None`, + + - if the default data type corresponding to the data type "kind" (integer or floating-point) of `x` has a smaller range of values than the data type of `x` (e.g., `x` has data type `int64` and the default data type is `int32`, or `x` has data type `uint64` and the default data type is `int64`), the returned array must have the same data type as `x`. + - otherwise, the returned array must have the default data type corresponding to the data type "kind" (integer or floating-point) of `x`. + + If the data type (either specified or resolved) differs from the data type of `x`, the input array should be cast to the specified data type before computing the sum. Default: `None`. + + ```{note} + This keyword argument is intended to help prevent data type overflows. + ``` + - **keepdims**: _bool_ - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. @@ -207,7 +233,7 @@ For an input array `x`, let `N` equal the number of elements over which to compu - **out**: _<array>_ - - if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have the same data type as `x`. + - if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the `dtype` parameter above. (function-var)= ### var(x, /, *, axis=None, correction=0.0, keepdims=False) From d57a1f8ff1a7ac9478155b75da5072d1f8e0ece0 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Sep 2021 01:59:50 -0700 Subject: [PATCH 057/551] Rename (and move) `transpose` to `permute_dims` (#247) * Rename (and move) `transpose` to `permute` * Remove specification for `linalg.transpose` * Rename function to `permute_dims`, make `axes` argument required, and update reference --- spec/API_specification/array_object.md | 2 +- .../manipulation_functions.md | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 0b0ca24f1..9569f0168 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -274,7 +274,7 @@ Transpose of the array. The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. ```{note} -Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional `permute` interface found in this specification. +Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional `permute_dims` interface found in this specification. ``` #### Returns diff --git a/spec/API_specification/manipulation_functions.md b/spec/API_specification/manipulation_functions.md index e1e0e98ea..1f140bcb0 100644 --- a/spec/API_specification/manipulation_functions.md +++ b/spec/API_specification/manipulation_functions.md @@ -80,6 +80,27 @@ Reverses the order of elements in an array along the given axis. The shape of th - an output array having the same data type and shape as `x` and whose elements, relative to `x`, are reordered. +(function-permute-dims)= +### permute_dims(x, /, axes) + +Permutes the axes (dimensions) of an array `x`. + +#### Parameters + +- **x**: _<array>_ + + - input array. + +- **axes**: _Tuple\[ int, ... ]_ + + - tuple containing a permutation of `(0, 1, ..., N-1)` where `N` is the number of axes (dimensions) of `x`. + +#### Returns + +- **out**: _<array>_ + + - an array containing the axes permutation. The returned array must have the same data type as `x`. + (function-reshape)= ### reshape(x, /, shape) From 5593253dd86ce16e6e77d646d2c36cedff1d156a Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Sep 2021 02:05:25 -0700 Subject: [PATCH 058/551] Add specifications for returning upper (`triu`) and lower (`tril`) triangular matrices (#243) * Add `triu` and `tril` specifications * Fix typo and remove `device` keyword * Add note about allocation * Fix missing backticks --- spec/API_specification/creation_functions.md | 82 +++++++++++++++++--- 1 file changed, 70 insertions(+), 12 deletions(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index b482c6d06..505708f30 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -41,7 +41,7 @@ This function cannot guarantee that the interval does not include the `stop` val - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. #### Returns @@ -72,7 +72,7 @@ Convert the input to an array. - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. - **copy**: _Optional\[ bool ]_ @@ -102,7 +102,7 @@ Returns an uninitialized array having a specified `shape`. - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. #### Returns @@ -127,7 +127,7 @@ Returns an uninitialized array with the same `shape` as an input array `x`. - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. #### Returns @@ -160,7 +160,7 @@ Returns a two-dimensional array with ones on the `k`th diagonal and zeros elsewh - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. #### Returns @@ -214,7 +214,7 @@ Returns a new array having a specified `shape` and filled with `fill_value`. - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. #### Returns @@ -247,7 +247,7 @@ Returns a new array filled with `fill_value` and having the same `shape` as an i - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. #### Returns @@ -285,7 +285,7 @@ Returns evenly spaced numbers over a specified interval. - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. - **endpoint**: _bool_ @@ -345,7 +345,7 @@ Returns a new array having a specified `shape` and filled with ones. - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. #### Returns @@ -370,7 +370,7 @@ Returns a new array filled with ones and having the same `shape` as an input arr - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. #### Returns @@ -378,6 +378,64 @@ Returns a new array filled with ones and having the same `shape` as an input arr - an array having the same shape as `x` and filled with ones. +(function-tril)= +### tril(x, /, *, k=0) + +Returns the lower triangular part of a matrix (or a stack of matrices) `x`. + +```{note} +The lower triangular part of the matrix is defined as the elements on and below the specified diagonal `k`. +``` + +#### Parameters + +- **x**: _<array>_ + + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. + +- **k**: _int_ + + - diagonal above which to zero elements. If `k = 0`, the diagonal is the main diagonal. If `k < 0`, the diagonal is below the main diagonal. If `k > 0`, the diagonal is above the main diagonal. Default: `0`. + + ```{note} + The main diagonal is defined as the set of indices `{(i, i)}` for `i` on the interval `[0, min(M, N) - 1]`. + ``` + +#### Returns + +- **out**: _<array>_ + + - an array containing the lower triangular part(s). The returned array must have the same shape and data type as `x`. All elements above the specified diagonal `k` must be zeroed. The returned array should be allocated on the same device as `x`. + +(function-triu)= +### triu(x, /, *, k=0) + +Returns the upper triangular part of a matrix (or a stack of matrices) `x`. + +```{note} +The upper triangular part of the matrix is defined as the elements on and above the specified diagonal `k`. +``` + +#### Parameters + +- **x**: _<array>_ + + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. + +- **k**: _int_ + + - diagonal below which to zero elements. If `k = 0`, the diagonal is the main diagonal. If `k < 0`, the diagonal is below the main diagonal. If `k > 0`, the diagonal is above the main diagonal. Default: `0`. + + ```{note} + The main diagonal is defined as the set of indices `{(i, i)}` for `i` on the interval `[0, min(M, N) - 1]`. + ``` + +#### Returns + +- **out**: _<array>_ + + - an array containing the upper triangular part(s). The returned array must have the same shape and data type as `x`. All elements below the specified diagonal `k` must be zeroed. The returned array should be allocated on the same device as `x`. + (function-zeros)= ### zeros(shape, *, dtype=None, device=None) @@ -395,7 +453,7 @@ Returns a new array having a specified `shape` and filled with zeros. - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. Default: `None`. + - device on which to place the created array. Default: `None`. #### Returns @@ -420,7 +478,7 @@ Returns a new array filled with zeros and having the same `shape` as an input ar - **device**: _Optional\[ <device> ]_ - - device to place the created array on, if given. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. #### Returns From b0b23beb8cafc665fdaeee49eb9702b6965df540 Mon Sep 17 00:00:00 2001 From: Lezcano Date: Mon, 20 Sep 2021 10:10:31 +0100 Subject: [PATCH 059/551] Remove upper keyword from `eigh` and `eigvalsh`. (#226) * Remove upper keyword * Ensure arguments are positional-only Co-authored-by: Athan --- spec/extensions/linear_algebra_functions.md | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index a069d6a03..ead2dfefe 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -172,7 +172,7 @@ Returns the specified diagonals of a matrix (or a stack of matrices) `x`. _TODO: this requires complex number support to be added to the specification._ (function-linalg-eigh)= -### linalg.eigh(x, /, *, upper=False) +### linalg.eigh(x, /) Returns the eigenvalues and eigenvectors of a symmetric matrix (or a stack of symmetric matrices) `x`. @@ -184,10 +184,6 @@ Returns the eigenvalues and eigenvectors of a symmetric matrix (or a stack of sy - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must have a floating-point data type. -- **upper**: _bool_ - - - If `True`, use the upper-triangular part to compute the eigenvalues and eigenvectors. If `False`, use the lower-triangular part to compute the eigenvalues and eigenvectors. Default: `False`. - #### Returns - **out**: _Tuple\[ <array> ]_ @@ -210,7 +206,7 @@ Eigenvalue sort order is left unspecified. _TODO: this requires complex number support to be added to the specification._ (function-linalg-eigvalsh)= -### linalg.eigvalsh(x, /, *, upper=False) +### linalg.eigvalsh(x, /) Computes the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) `x`. @@ -222,10 +218,6 @@ Computes the eigenvalues of a symmetric matrix (or a stack of symmetric matrices - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must have a floating-point data type. -- **upper**: _bool_ - - - If `True`, use the upper-triangular part to compute the eigenvalues. If `False`, use the lower-triangular part to compute the eigenvalues. Default: `False`. - #### Returns - **out**: _<array>_ From 12c2bd93cd29c659cb700170ca54d203e42172de Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 20 Sep 2021 03:16:56 -0600 Subject: [PATCH 060/551] Clarify the exact bounds of what is required for slices (#138) * Clarify the exact bounds of what is required for slices * Apply suggestions from code review Co-authored-by: Athan * Fix some markdown Co-authored-by: Athan --- spec/API_specification/indexing.md | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 23998a8cf..e673bec03 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -114,16 +114,19 @@ Using a slice to index a single array axis must adhere to the following rules. L ```{note} -This specification does not require "clipping" out-of-bounds indices (i.e., requiring the starting and stopping indices `i` and `j` be bound by `0` and `n`, respectively). - -_Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ +This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where `0:100` and `0:10` are equivalent on a list of length `10`. ``` -```{note} +The following ranges for the start and stop values of a slice must be supported. Let `n` be the axis (dimension) size being sliced. For a slice `i:j:k`, the behavior specified above should be implemented for the following: + +- `i` or `j` omitted (`None`). +- `-n <= i <= max(0, n - 1)`. +- For `k > 0` or `k` omitted (`None`), `-n <= j <= n`. +- For `k < 0`, `-n - 1 <= j <= max(0, n - 1)`. -This specification leaves unspecified the behavior of indexing a single array axis with an out-of-bounds slice (i.e., a slice which does not select any array axis elements). +The behavior outside of these bounds is unspecified. -_Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to return an empty array (whose axis (dimension) size along the indexed axis is `0`), raise an exception, or some other behavior depending on device requirements and performance considerations._ +_Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip (consistent with Python `list` slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ ``` ## Multi-axis Indexing From 7c638f30f2d73bced0cbe8d84ea0c12a8e1062a7 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Sep 2021 03:12:33 -0700 Subject: [PATCH 061/551] Remove `einsum` TODO (#269) The addition of `einsum` is delayed until the 2022 specification revision. --- spec/API_specification/linear_algebra_functions.md | 5 ----- spec/extensions/linear_algebra_functions.md | 5 ----- 2 files changed, 10 deletions(-) diff --git a/spec/API_specification/linear_algebra_functions.md b/spec/API_specification/linear_algebra_functions.md index fb8b0f4ec..207dee70c 100644 --- a/spec/API_specification/linear_algebra_functions.md +++ b/spec/API_specification/linear_algebra_functions.md @@ -15,11 +15,6 @@ A conforming implementation of the array API standard must provide and support t -(function-einsum)= -### einsum() - -TODO - (function-matmul)= ### matmul(x1, x2, /) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index ead2dfefe..bb137f043 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -229,11 +229,6 @@ Computes the eigenvalues of a symmetric matrix (or a stack of symmetric matrices Eigenvalue sort order is left unspecified. ``` -(function-linalg-einsum)= -### linalg.einsum() - -Alias for {ref}`function-einsum`. - (function-linalg-inv)= ### linalg.inv(x, /) From 5565ac4fc8c3f2f105c6df42fbab637f6dba69de Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 20 Sep 2021 04:21:32 -0600 Subject: [PATCH 062/551] Indicate that abs() of the minimum integer value for signed dtypes is undefined (#250) * Indicate that abs() of the minimum integer value for signed dtypes is undefined * Move the abs(smallest signed integer) text into a note * Update copy * Remove blank line * Update copy "smallest" is ambiguous, as could mean `0` or the minimum value (e.g., `-128` for `int8`). * Fix missing article Co-authored-by: Athan --- spec/API_specification/elementwise_functions.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 570119540..d19137fc1 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -24,6 +24,10 @@ A conforming implementation of the array API standard must provide and support t Calculates the absolute value for each element `x_i` of the input array `x` (i.e., the element-wise result has the same magnitude as the respective element in `x` but has positive sign). +```{note} +For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. +``` + #### Special Cases For floating-point operands, From 4e51c5be33febeaa42fac0d8dee98121a4ef60e8 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Sep 2021 03:29:33 -0700 Subject: [PATCH 063/551] Add note to `negative` for signed integer dtype behavior (#270) * Add note and remove empty lines * Add dunder method note --- spec/API_specification/array_object.md | 4 ++++ spec/API_specification/elementwise_functions.md | 10 ++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 9569f0168..4459d8fd8 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -934,6 +934,10 @@ Element-wise results must equal the results returned by the equivalent element-w Evaluates `-self_i` for each element of an array instance. +```{note} +For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. +``` + #### Parameters - **self**: _<array>_ diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index d19137fc1..35210d7b1 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -128,7 +128,6 @@ For floating-point operands, - In the remaining cases, when neither `infinity`, `+0`, `-0`, nor a `NaN` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. ```{note} - Floating-point addition is a commutative operation, but not always associative. ``` @@ -237,7 +236,6 @@ Calculates an implementation-dependent approximation of the inverse tangent of t The mathematical signs of `x1_i` and `x2_i` determine the quadrant of each element-wise result. The quadrant (i.e., branch) is chosen such that each element-wise result is the signed angle in radians between the ray ending at the origin and passing through the point `(1,0)` and the ray ending at the origin and passing through the point `(x2_i, x1_i)`. ```{note} - Note the role reversal: the "y-coordinate" is the first function parameter; the "x-coordinate" is the second function parameter. The parameter order is intentional and traditional for the two-argument inverse tangent function where the y-coordinate argument is first and the x-coordinate argument is second. ``` @@ -402,7 +400,6 @@ Computes the bitwise OR of the underlying binary representation of each element Shifts the bits of each element `x1_i` of the input array `x1` to the right according to the respective element `x2_i` of the input array `x2`. ```{note} - This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. ``` @@ -620,7 +617,6 @@ For floating-point operands, Calculates an implementation-dependent approximation to `exp(x)-1`, having domain `[-infinity, +infinity]` and codomain `[-1, +infinity]`, for each element `x_i` of the input array `x`. ```{note} - The purpose of this function is to calculate `exp(x)-1.0` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply `exp(x)-1.0`. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. ``` @@ -856,7 +852,6 @@ For floating-point operands, Calculates an implementation-dependent approximation to `log(1+x)`, where `log` refers to the natural (base `e`) logarithm, having domain `[-1, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` of the input array `x`. ```{note} - The purpose of this function is to calculate `log(1+x)` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply `log(1+x)`. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. ``` @@ -1085,7 +1080,6 @@ For floating-point operands, - In the remaining cases, where neither `infinity` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. ```{note} - Floating-point multiplication is not always associative due to finite precision. ``` @@ -1110,6 +1104,10 @@ Floating-point multiplication is not always associative due to finite precision. Computes the numerical negative of each element `x_i` (i.e., `y_i = -x_i`) of the input array `x`. +```{note} +For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. +``` + #### Parameters - **x**: _<array>_ From 614f8c1bb84e129512c170ed5f7858bbd52212ce Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Sep 2021 03:34:35 -0700 Subject: [PATCH 064/551] Add note to `__abs__` concerning signed integer dtype behavior (#271) See also [gh-250](https://github.com/data-apis/array-api/pull/250). --- spec/API_specification/array_object.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 4459d8fd8..823fdc6b2 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -294,6 +294,10 @@ Limiting the transpose to two-dimensional arrays (matrices) deviates from the Nu Calculates the absolute value for each element of an array instance (i.e., the element-wise result has the same magnitude as the respective element but has positive sign). +```{note} +For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. +``` + #### Special Cases For floating-point operands, let `self` equal `x`. From 0c99ea2d9b6805ef2e8e36516e863f3c7376f236 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Sep 2021 10:11:21 -0700 Subject: [PATCH 065/551] Update device guidance for `*_like` functions (#268) The default behavior is changed is infer the output array device from the input array when `device` is `None`. --- spec/API_specification/creation_functions.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index 505708f30..7b22063da 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -127,7 +127,7 @@ Returns an uninitialized array with the same `shape` as an input array `x`. - **device**: _Optional\[ <device> ]_ - - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. #### Returns @@ -247,7 +247,7 @@ Returns a new array filled with `fill_value` and having the same `shape` as an i - **device**: _Optional\[ <device> ]_ - - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. #### Returns @@ -370,7 +370,7 @@ Returns a new array filled with ones and having the same `shape` as an input arr - **device**: _Optional\[ <device> ]_ - - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. #### Returns @@ -478,7 +478,7 @@ Returns a new array filled with zeros and having the same `shape` as an input ar - **device**: _Optional\[ <device> ]_ - - device on which to place the created array. If `device` is `None`, the default device must be used, not `x.device`. Default: `None`. + - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. #### Returns From 70fcdd7d2361808934da13032dbeb8cda51d6e2f Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Sep 2021 14:23:51 -0700 Subject: [PATCH 066/551] Require that data type objects implement `__eq__` in order to test for data type equality (#273) * Specify `__eq__` * Fix reference --- spec/API_specification/data_types.md | 43 +++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/data_types.md b/spec/API_specification/data_types.md index 37f528c7a..7e295da1e 100644 --- a/spec/API_specification/data_types.md +++ b/spec/API_specification/data_types.md @@ -64,14 +64,49 @@ for more details. ::: ```{note} -Data types ("dtypes") are objects that can be used as `dtype` specifiers in functions and methods (e.g., `zeros((2, 3), dtype=float32)`). A conforming implementation may add methods or attributes to data type objects; however, these methods and attributes are not included in this specification. +A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. +``` -Implementations may provide other ways to specify data types (e.g., -`zeros((2, 3), dtype='f4')`); however, these are not included in this specification. +(data-type-objects)= +## Data Type Objects -A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. +Data types ("dtypes") are objects which are used as `dtype` specifiers in functions and methods (e.g., `zeros((2, 3), dtype=float32)`). + +```{note} +A conforming implementation may add additional methods or attributes to data type objects beyond those described in this specification. ``` +```{note} +Implementations may provide other ways to specify data types (e.g., `zeros((2, 3), dtype='f4')`) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. +``` + +A conforming implementation of the array API standard must provide and support data type objects having the following attributes and methods. + +### Methods + + + +(data-type-method-__eq__)= +### \_\_eq\_\_(self, other, /) + +Computes the truth value of `self == other` in order to test for data type object equality. + +#### Parameters + +- **self**: _<dtype>_ + + - data type instance. May be any supported data type. + +- **other**: _<dtype>_ + + - other data type instance. May be any supported data type. + +#### Returns + +- **out**: _<bool>_ + + - a boolean indicating whether the data type objects are equal. + (data-type-defaults)= ## Default Data Types From 77a921afb111b4771c69793a5a6dcdef29043496 Mon Sep 17 00:00:00 2001 From: Bas van Beek <43369155+BvB93@users.noreply.github.com> Date: Tue, 28 Sep 2021 19:35:36 +0200 Subject: [PATCH 067/551] Remove the `Sequence` encapsulation of variadic parameters (#276) * Remove the `Sequence` encapsulation of variadic parameters * Explicitly state that variadic parameters can take an arbitrary number of objects --- spec/API_specification/creation_functions.md | 4 ++-- spec/API_specification/data_type_functions.md | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index 7b22063da..8adf44e1e 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -304,9 +304,9 @@ Returns coordinate matrices from coordinate vectors. #### Parameters -- **arrays**: _Sequence\[ <array> ]_ +- **arrays**: _<array>_ - - one-dimensional arrays representing grid coordinates. Must have a numeric data type. + - an arbitrary number of one-dimensional arrays representing grid coordinates. Must have numeric data types. - **indexing**: _str_ diff --git a/spec/API_specification/data_type_functions.md b/spec/API_specification/data_type_functions.md index 5a8165411..11f893a97 100644 --- a/spec/API_specification/data_type_functions.md +++ b/spec/API_specification/data_type_functions.md @@ -14,9 +14,9 @@ Broadcasts one or more arrays against one another. #### Parameters -- **arrays**: _Sequence\[ <array> ]_ +- **arrays**: _<array>_ - - arrays to broadcast. + - an arbitrary number of to-be broadcasted arrays. #### Returns @@ -134,9 +134,9 @@ If provided mixed dtypes (e.g., integer and floating-point), the returned dtype #### Parameters -- **arrays_and_dtypes**: _Sequence\[ Union\[ <array>, <dtype> \] \]_ +- **arrays_and_dtypes**: _Union\[ <array>, <dtype> \]_ - - input arrays and dtypes. + - an arbitrary number of input arrays and/or dtypes. #### Returns From be6d7c51ffb4453a9deffdaa78dcbef2acbe0f12 Mon Sep 17 00:00:00 2001 From: Bas van Beek <43369155+BvB93@users.noreply.github.com> Date: Wed, 29 Sep 2021 22:30:50 +0200 Subject: [PATCH 068/551] disallow `k=None` for the `eye` function (#278) --- spec/API_specification/creation_functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index 8adf44e1e..990ff6ae5 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -150,7 +150,7 @@ Returns a two-dimensional array with ones on the `k`th diagonal and zeros elsewh - number of columns in the output array. If `None`, the default number of columns in the output array is equal to `n_rows`. Default: `None`. -- **k**: _Optional\[ int ]_ +- **k**: _int_ - index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and `0` to the main diagonal. Default: `0`. From c58765618505eed0ffb1a4a2ce671e4f3e04564e Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 4 Oct 2021 09:36:27 -0700 Subject: [PATCH 069/551] Require single-axis indexing expressions be provided for each axis (#272) * Remove blank lines and clean-up * Require that single axis indexing expressions be provided for each axis * Move item * Update copy * Update copy --- spec/API_specification/indexing.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index e673bec03..c448b01be 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -89,12 +89,10 @@ j > i + (m-1)k ``` ```{note} - For `i` on the interval `[0, n)` (where `n` is the axis size), `j` on the interval `(0, n]`, `i` less than `j`, and positive step `k`, a starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. ``` ```{note} - Using a slice to index into a single array axis should select the same elements as using a slice to index a Python list of the same size. ``` @@ -113,7 +111,6 @@ Using a slice to index a single array axis must adhere to the following rules. L - Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). ```{note} - This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where `0:100` and `0:10` are equivalent on a list of length `10`. ``` @@ -126,6 +123,7 @@ The following ranges for the start and stop values of a slice must be supported. The behavior outside of these bounds is unspecified. +```{note} _Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip (consistent with Python `list` slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ ``` @@ -136,7 +134,6 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). ```{note} - In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. ``` @@ -148,14 +145,19 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). -- If the number of provided single-axis indexing expressions is less than `N`, then `:` must be assumed for the remaining dimensions (e.g., if `A` has rank `2`, `A[2:10] == A[2:10, :]`). +- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. -- An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is greater than `N`. +- Except in the case of providing an ellipsis to index all trailing dimensions (e.g., `A[2:10, ...]`), the number of provided single-axis indexing expressions must equal `N`. For example, if `A` has rank `2`, a single-axis indexing expression must be explicitly provided for both axes (e.g., `A[2:10, :]`). An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is less than `N`. -- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. + ```{note} + Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. -```{note} + To perform flat indexing, use `reshape(x, (-1,))[integer]`. + ``` + +- An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is greater than `N`. +```{note} This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. _Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to `0`, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ @@ -174,7 +176,6 @@ An array must support indexing where the **sole index** is an `M`-dimensional bo - If `N >= M`, then `A[B]` must replace the first `M` dimensions of `A` with a single dimension having a size equal to the number of `True` elements in `B`. The values in the resulting array must be in row-major (C-style order); this is equivalent to `A[nonzero(B)]`. ```{note} - For example, if `N == M == 2`, indexing `A` via a boolean array `B` will return a one-dimensional array whose size is equal to the number of `True` elements in `B`. ``` @@ -191,6 +192,5 @@ An array must support indexing where the **sole index** is an `M`-dimensional bo The result of an indexing operation (e.g., multi-axis indexing, boolean array indexing, etc) must be an array of the same data type as the indexed array. ```{note} - The specified return value behavior includes indexing operations which return a single value (e.g., accessing a single element within a one-dimensional array). ``` From 436c97f773c86ea06dddca8d3810701234b867c1 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 4 Oct 2021 09:54:40 -0700 Subject: [PATCH 070/551] Update guidance for output array dtype inference in `full_like` (#274) * Update guidance on full-like dtype inferrence * Update copy --- spec/API_specification/creation_functions.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index 990ff6ae5..cf8355c5d 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -239,10 +239,14 @@ Returns a new array filled with `fill_value` and having the same `shape` as an i - **dtype**: _Optional\[ <dtype> ]_ - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `fill_value` (see {ref}`function-full`). Default: `None`. + - output array data type. If `dtype` is `None`, the output array data type must be inferred from `x`. Default: `None`. ```{note} - If `dtype` is `None` and the `fill_value` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + If `dtype` is `None` and the `fill_value` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + ``` + + ```{note} + If `dtype` is `None` and the `fill_value` has a data type (`int` or `float`) which is not of the same data type kind as the resolved output array data type (see {ref}`type-promotion`), behavior is unspecified and, thus, implementation-defined. ``` - **device**: _Optional\[ <device> ]_ From 43edaa2466f8509ff850dca3eef865cb5941b354 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 4 Oct 2021 13:34:34 -0700 Subject: [PATCH 071/551] Update the default `axis` value for `vecdot` to be `-1` (#281) --- spec/API_specification/linear_algebra_functions.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/linear_algebra_functions.md b/spec/API_specification/linear_algebra_functions.md index 207dee70c..139dea215 100644 --- a/spec/API_specification/linear_algebra_functions.md +++ b/spec/API_specification/linear_algebra_functions.md @@ -106,7 +106,7 @@ Returns a tensor contraction of `x1` and `x2` over specific axes. - an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array `x1`, followed by the non-contracted axes (dimensions) of the second array `x2`. The returned array must have a data type determined by {ref}`type-promotion`. (function-vecdot)= -### vecdot(x1, x2, /, *, axis=None) +### vecdot(x1, x2, /, *, axis=-1) Computes the (vector) dot product of two arrays. @@ -120,9 +120,9 @@ Computes the (vector) dot product of two arrays. - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. -- **axis**: _Optional\[ int ]_ +- **axis**: _int_ - - axis over which to compute the dot product. Must be an integer on the interval `[-N, N)`, where `N` is the rank (number of dimensions) of the shape determined according to {ref}`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where `-1` refers to the last dimension). If `None`, the function must compute the dot product over the last axis. Default: `None`. + - axis over which to compute the dot product. Must be an integer on the interval `[-N, N)`, where `N` is the rank (number of dimensions) of the shape determined according to {ref}`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where `-1` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: `-1`. #### Returns From cd77bf91730b38e6e27a2ad6c606a1e99f6dd90b Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 7 Oct 2021 02:57:30 -0600 Subject: [PATCH 072/551] Small fixes to the linalg extension (#277) * Add a cross-reference to the linalg extension in the linear algebra section * Fix a reference to transpose() to matrix_transpose() * Remove TODO-ed linalg functions eig() and eigvals() Instead just reference that they will be added in a later version of the spec in notes. * Use a better header title for the linear algebra extension page * Fix the return type annotation for svdvals The annotation was based on a previous version where the return type was polymorphic. * Fix the type hints for vector_norm() * Remove comment Co-authored-by: Athan --- spec/extensions/linear_algebra_functions.md | 29 +++++++++++---------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index bb137f043..15a2e7efe 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -1,4 +1,5 @@ -# Linear Algebra Functions +(linear-algebra-extension)= +# Linear Algebra Extension > Array API specification for linear algebra functions. @@ -37,7 +38,7 @@ Accordingly, the standardization process affords the opportunity to reduce inter Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: - - `transpose`: computing the transpose. + - `matrix_transpose`: computing the transpose. - `diagonal`: returning the diagonal. 3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. @@ -166,11 +167,6 @@ Returns the specified diagonals of a matrix (or a stack of matrices) `x`. - an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as `x`. -(function-linalg-eig)= -### linalg.eig() - -_TODO: this requires complex number support to be added to the specification._ - (function-linalg-eigh)= ### linalg.eigh(x, /) @@ -200,10 +196,10 @@ Returns the eigenvalues and eigenvectors of a symmetric matrix (or a stack of sy Eigenvalue sort order is left unspecified. ``` -(function-linalg-eigvals)= -### linalg.eigvals() - -_TODO: this requires complex number support to be added to the specification._ +```{note} +The function `eig` will be added in a future version of the specification, +as it requires complex number support. +``` (function-linalg-eigvalsh)= ### linalg.eigvalsh(x, /) @@ -229,6 +225,11 @@ Computes the eigenvalues of a symmetric matrix (or a stack of symmetric matrices Eigenvalue sort order is left unspecified. ``` +```{note} +The function `eigvals` will be added in a future version of the specification, +as it requires complex number support. +``` + (function-linalg-inv)= ### linalg.inv(x, /) @@ -512,7 +513,7 @@ Computes the singular values of a matrix (or a stack of matrices) `x`. #### Returns -- **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ +- **out**: _<array>_ - an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. The returned array must have the same floating-point data type as `x`. @@ -570,7 +571,7 @@ Computes the vector norm of a vector (or batch of vectors) `x`. - input array. Should have a floating-point data type. -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, int ] ] ]_ +- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - If an integer, `axis` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, `axis` specifies the axes (dimensions) along which to compute batched vector norms. If `None`, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: `None`. @@ -578,7 +579,7 @@ Computes the vector norm of a vector (or batch of vectors) `x`. - If `True`, the axes (dimensions) specified by `axis` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the axes (dimensions) specified by `axis` must not be included in the result. Default: `False`. -- **ord**: _Optional\[ Union\[ int, float, Literal\[ inf, -inf ] ] ]_ +- **ord**: _Union\[ int, float, Literal\[ inf, -inf ] ]_ - order of the norm. The following mathematical norms must be supported: | ord | description | From d93dc92f87f5400a0cddbcef136ed980b5949757 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 18 Oct 2021 14:41:51 -0700 Subject: [PATCH 073/551] Fix and update guidance for multi-axis indexing (#287) --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index c448b01be..eca49927b 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -147,7 +147,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. -- Except in the case of providing an ellipsis to index all trailing dimensions (e.g., `A[2:10, ...]`), the number of provided single-axis indexing expressions must equal `N`. For example, if `A` has rank `2`, a single-axis indexing expression must be explicitly provided for both axes (e.g., `A[2:10, :]`). An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is less than `N`. +- Except in the case of providing a single ellipsis (e.g., `A[2:10, ...]` or `A[1:, ..., 2:5]`), the number of provided single-axis indexing expressions should equal `N`. For example, if `A` has rank `2`, a single-axis indexing expression should be explicitly provided for both axes (e.g., `A[2:10, :]`). An `IndexError` exception should be raised if the number of provided single-axis indexing expressions is less than `N`. ```{note} Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. From e8fc6123d43da610efec3725e7a6e126016e77b8 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Tue, 19 Oct 2021 13:22:58 -0400 Subject: [PATCH 074/551] Clarify default device for `asarray` (#286) --- spec/API_specification/creation_functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index cf8355c5d..dc0f8374f 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -72,7 +72,7 @@ Convert the input to an array. - **device**: _Optional\[ <device> ]_ - - device on which to place the created array. Default: `None`. + - device on which to place the created array. If `device` is `None` and `x` is either an array or an object supporting DLPack, the output array device must be inferred from `x`. Default: `None`. - **copy**: _Optional\[ bool ]_ From f9f9bc4b17dadf8a8a3aa5b18dc684b93b55217e Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 20 Oct 2021 17:44:13 -0700 Subject: [PATCH 075/551] Split `unique` into separate functions (#275) * Split `unique` into separate functions * Update copy * Fix shape guidance * Add notes * Rename function to avoid breaking backward compat * Specify the `values` array data type --- spec/API_specification/set_functions.md | 78 ++++++++++++++++++------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/spec/API_specification/set_functions.md b/spec/API_specification/set_functions.md index e00b116f9..3f3a9d192 100644 --- a/spec/API_specification/set_functions.md +++ b/spec/API_specification/set_functions.md @@ -12,13 +12,13 @@ A conforming implementation of the array API standard must provide and support t -(function-unique)= -### unique(x, /, *, return_counts=False, return_index=False, return_inverse=False) +(function-unique-all)= +### unique_all(x, /) :::{admonition} Data-dependent output shape :class: important -The shapes of one or more of output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. +The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. ::: Returns the unique elements of an input array `x`. @@ -29,40 +29,74 @@ Returns the unique elements of an input array `x`. - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. -- **return_counts**: _bool_ +#### Returns + +- **out**: _Tuple\[ <array>, <array>, <array>, <array> ]_ - - If `True`, the function must also return the number of times each unique element occurs in `x`. Default: `False`. + - a namedtuple `(values, indices, inverse_indices, counts)` whose -- **return_index**: _bool_ + - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. + - second element must have the field name `indices` and must be an array containing the indices (first occurrences) of `x` that result in `values`. The array must have the same shape as `values` and must have the default integer data type. + - third element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and must have the default integer data type. + - fourth element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default integer data type. - - If `True`, the function must also return the indices (first occurrences) of `x` that result in the unique array. Default: `False`. + ```{note} + The order of unique elements is not specified and may vary between implementations. + ``` -- **return_inverse**: _bool_ +(function-unique-inverse)= +### unique_inverse(x, /) - - If `True`, the function must also return the indices of the unique array that reconstruct `x`. Default: `False`. +Returns the unique elements of an input array `x` and the indices from the set of unique elements that reconstruct `x`. + +:::{admonition} Data-dependent output shape +:class: important + +The shape of one of the output arrays for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. +::: + +#### Parameters + +- **x**: _<array>_ + + - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. #### Returns -- **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ +- **out**: _Tuple\[ <array>, <array> ]_ - - if `return_counts`, `return_index`, and `return_inverse` are all `False`, an array containing the set of unique elements in `x`; otherwise, a tuple containing two or more of the following arrays (in order): + - a namedtuple `(values, inverse_indices)` whose - - **unique**: _<array>_ + - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. + - second element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and have the default integer data type. - - an array containing the set of unique elements in `x`. The returned array must have the same data type as `x`. + ```{note} + The order of unique elements is not specified and may vary between implementations. + ``` - ```{note} - The order of elements is not specified, and may vary between implementations. - ``` +(function-unique-values)= +### unique_values(x, /) - - **indices**: _<array>_ +:::{admonition} Data-dependent output shape +:class: important + +The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. +::: + +Returns the unique elements of an input array `x`. - - an array containing the indices (first occurrences) of `x` that result in `unique`. The returned array must have the default integer data type. +#### Parameters + +- **x**: _<array>_ - - **inverse**: _<array>_ + - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. + +#### Returns - - an array containing the indices of `unique` that reconstruct `x`. The returned array must have the default integer data type. +- **out**: _<array>_ - - **counts**: _<array>_ + - an array containing the set of unique elements in `x`. The returned array must have the same data type as `x`. - - an array containing the number of times each unique element occurs in `x`. The returned array must have the default integer data type. + ```{note} + The order of unique elements is not specified and may vary between implementations. + ``` \ No newline at end of file From f267ebd3505bc13d9f49569021669b6742bcd046 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sat, 23 Oct 2021 02:23:14 -0500 Subject: [PATCH 076/551] Fix a typo in the indexing specification (#292) The slice start bounds were off-by-one, preventing slices that should be valid to produce an empty slice. --- spec/API_specification/indexing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index eca49927b..394d376d4 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -117,7 +117,7 @@ This specification does not require "clipping" out-of-bounds slice indices. This The following ranges for the start and stop values of a slice must be supported. Let `n` be the axis (dimension) size being sliced. For a slice `i:j:k`, the behavior specified above should be implemented for the following: - `i` or `j` omitted (`None`). -- `-n <= i <= max(0, n - 1)`. +- `-n <= i <= n`. - For `k > 0` or `k` omitted (`None`), `-n <= j <= n`. - For `k < 0`, `-n - 1 <= j <= max(0, n - 1)`. From 2461de35e024e7a834890568c2ae986b4b6474d1 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 1 Nov 2021 10:32:48 -0700 Subject: [PATCH 077/551] Add specification for explicitly casting an array to a specified dtype (#290) * Add astype API and restrict asarray to type promotion rules * Update copy * Update copy * Add support for a `copy` keyword * Restrict `docutils` version --- requirements.txt | 1 + spec/API_specification/creation_functions.md | 20 ++++++++++--- spec/API_specification/data_type_functions.md | 30 +++++++++++++++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/requirements.txt b/requirements.txt index fa2e7d09f..5df0b2504 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,4 @@ sphinx-material==0.0.30 myst-parser sphinx_markdown_tables sphinx_copybutton +docutils<0.18 diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index dc0f8374f..6cb52aea0 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -59,7 +59,7 @@ Convert the input to an array. - **obj**: _Union\[ <array>, bool, int, float, NestedSequence\[ bool | int | float ], SupportsDLPack, SupportsBufferProtocol ]_ - - Object to be converted to an array. Can be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting DLPack or the Python buffer protocol. + - object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting DLPack or the Python buffer protocol. :::{tip} An object supporting DLPack has `__dlpack__` and `__dlpack_device__` methods. @@ -68,7 +68,19 @@ Convert the input to an array. - **dtype**: _Optional\[ <dtype> ]_ - - output array data type. If `dtype` is `None`, the output array data type must be inferred from the data type(s) in `obj`. If all input values are Python scalars, then if they're all `bool` the output dtype will be `bool`; if they're a mix of `bool`s and `int` the output dtype will be the default integer data type; if they contain `float`s the output dtype will be the default floating-point data type. Default: `None`. + - output array data type. If `dtype` is `None`, the output array data type must be inferred from the data type(s) in `obj`. If all input values are Python scalars, then + + - if all values are of type `bool`, the output data type must be `bool`. + - if the values are a mixture of `bool`s and `int`, the output data type must be the default integer data type. + - if one or more values are `float`s, the output data type must be the default floating-point data type. + + Default: `None`. + + ```{note} + If `dtype` is not `None`, then array conversions should obey {ref}`type-promotion` rules. Conversions not specified according to {ref}`type-promotion` rules may or may not be permitted by a conforming array library. + + To perform an explicit cast, use {ref}`function-astype`. + ``` - **device**: _Optional\[ <device> ]_ @@ -76,13 +88,13 @@ Convert the input to an array. - **copy**: _Optional\[ bool ]_ - - Whether or not to make a copy of the input. If `True`, always copies. If `False`, never copies for input which supports DLPack or the buffer protocol, and raises `ValueError` in case that would be necessary. If `None`, reuses existing memory buffer if possible, copies otherwise. Default: `None`. + - boolean indicating whether or not to copy the input. If `True`, the function must always copy. If `False`, the function must never copy for input which supports DLPack or the buffer protocol and must raise a `ValueError` in case a copy would be necessary. If `None`, the function must reuse existing memory buffer if possible and copy otherwise. Default: `None`. #### Returns - **out**: _<array>_ - - An array containing the data from `obj`. + - an array containing the data from `obj`. (function-empty)= diff --git a/spec/API_specification/data_type_functions.md b/spec/API_specification/data_type_functions.md index 11f893a97..0f1dc512d 100644 --- a/spec/API_specification/data_type_functions.md +++ b/spec/API_specification/data_type_functions.md @@ -7,6 +7,36 @@ A conforming implementation of the array API standard must provide and support t ## Objects in API + +(function-astype)= +### astype(x, dtype, /, *, copy=True) + +Copies an array to a specified data type irrespective of {ref}`type-promotion` rules. + +```{note} +Casting floating-point `NaN` and `infinity` values to integral data types is not specified and is implementation-dependent. +``` + +#### Parameters + +- **x**: _<array>_ + + - array to cast. + +- **dtype**: _<dtype>_ + + - desired data type. + +- **copy**: _<bool>_ + + - specifies whether to copy an array when the specified `dtype` matches the data type of the input array `x`. If `True`, a newly allocated array must always be returned. If `False` and the specified `dtype` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated must be returned. Default: `True`. + +#### Returns + +- **out**: _<array>_ + + - an array having the specified data type. The returned array must have the same shape as `x`. + (function-broadcast_arrays)= ### broadcast_arrays(*arrays) From b9baefc118d27308ec7fd5a8773143ea3d75b874 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 1 Nov 2021 10:47:49 -0700 Subject: [PATCH 078/551] Add note concerning the casting of boolean input arrays (#296) --- spec/API_specification/data_type_functions.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/API_specification/data_type_functions.md b/spec/API_specification/data_type_functions.md index 0f1dc512d..69a595b93 100644 --- a/spec/API_specification/data_type_functions.md +++ b/spec/API_specification/data_type_functions.md @@ -17,6 +17,12 @@ Copies an array to a specified data type irrespective of {ref}`type-promotion` r Casting floating-point `NaN` and `infinity` values to integral data types is not specified and is implementation-dependent. ``` +```{note} +When casting a boolean input array to a numeric data type, a value of `True` must cast to a numeric value equal to `1`, and a value of `False` must cast to a numeric value equal to `0`. + +When casting a numeric input array to `bool`, a value of `0` must cast to `False`, and a non-zero value must cast to `True`. +``` + #### Parameters - **x**: _<array>_ From 44ccd65209832bab40b618a81d0b544d07e55f3f Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 1 Nov 2021 11:28:02 -0700 Subject: [PATCH 079/551] Add clarifying examples to note concerning tuple usage in multi-axis indexing (#280) * Add examples to note * Remove sentence * Add note * Add note regarding providing an empty tuple to a rank 0 array * Add note * Update note * Remove empty lines * Fix note * Add note --- spec/API_specification/indexing.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md index 394d376d4..f06cae9d3 100644 --- a/spec/API_specification/indexing.md +++ b/spec/API_specification/indexing.md @@ -17,21 +17,18 @@ To index a single array axis, an array must support standard Python indexing rul - **Valid** nonnegative indices must reside on the half-open interval `[0, n)`. ```{note} - This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. ``` - Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). ```{note} - A negative index `j` is equivalent to `n-j`; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. ``` - **Valid** negative indices must reside on the closed interval `[-n, -1]`. ```{note} - This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. ``` @@ -39,6 +36,10 @@ To index a single array axis, an array must support standard Python indexing rul - Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. +```{note} +The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. +``` + ### Slice Syntax The basic slice syntax is `i:j:k` where `i` is the starting index, `j` is the stopping index, and `k` is the step (`k != 0`). A slice may contain either one or two colons, with either an integer value or nothing on either side of each colon. The following are valid slices. @@ -60,7 +61,6 @@ A[i:j:k] ``` ```{note} - Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html#slice) API. From the perspective of `A`, the behavior of `A[i:j:k]` and `A[slice(i, j, k)]` is indistinguishable (i.e., both retrieve the same set of items from `__getitem__`). ``` @@ -134,7 +134,9 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). ```{note} - In Python, `x[(exp1, exp2, ..., expN)]` is equivalent to `x[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. + In Python, `A[(exp1, exp2, ..., expN)]` is equivalent to `A[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. + + Accordingly, if `A` has rank `1`, then `A[(2:10,)]` must be equivalent to `A[2:10]`. If `A` has rank `2`, then `A[(2:10, :)]` must be equivalent to `A[2:10, :]`. And so on and so forth. ``` - Providing a single nonnegative integer `i` as a single-axis index must index the same elements as the slice `i:i+1`. @@ -143,10 +145,20 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. + ```{note} + When providing a single integer as a single-axis index to an array of rank `1`, the result should be an array of rank `0`, not a NumPy scalar. Note that this behavior differs from NumPy. + ``` + - Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). - Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. +- Providing an empty tuple or an ellipsis to an array of rank `0` must result in an array of the same rank (i.e., if `A` has rank `0`, `A == A[()]` and `A == A[...]`). + + ```{note} + This behavior differs from NumPy where providing an empty tuple to an array of rank `0` returns a NumPy scalar. + ``` + - Except in the case of providing a single ellipsis (e.g., `A[2:10, ...]` or `A[1:, ..., 2:5]`), the number of provided single-axis indexing expressions should equal `N`. For example, if `A` has rank `2`, a single-axis indexing expression should be explicitly provided for both axes (e.g., `A[2:10, :]`). An `IndexError` exception should be raised if the number of provided single-axis indexing expressions is less than `N`. ```{note} From 5ecbce416aa46d642b98d9568625250fec323fc4 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Mon, 1 Nov 2021 14:51:30 -0400 Subject: [PATCH 080/551] Address device related issues (#259) * add to_device * clarify device object * clarify library-specific stream can be used * move -> copy * apply review comments * Apply suggestions from code review Co-authored-by: Athan * Update copy * Add linebreak. Co-authored-by: Athan --- spec/API_specification/array_object.md | 18 +++++++++++++++--- spec/design_topics/device_support.md | 19 ++++++++++++++----- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 823fdc6b2..ff5b1b46b 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -458,6 +458,10 @@ Exports the array for consumption by {ref}`function-from_dlpack` as a DLPack cap For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for `stream` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order `cl::sycl::queue`. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + ```{note} + Support for a `stream` value other than `None` is optional and implementation-dependent. + ``` + Device-specific notes: :::{admonition} CUDA @@ -1213,9 +1217,9 @@ Element-wise results must equal the results returned by the equivalent element-w ``` (method-to_device)= -### to\_device(self, device, /) +### to\_device(self, device, /, *, stream=None) -Move the array to the given device. +Copy the array from the device on which it currently resides to the specified `device`. #### Parameters @@ -1227,8 +1231,16 @@ Move the array to the given device. - a `device` object (see {ref}`device-support`). +- **stream**: _Optional\[ Union\[ int, Any ]]_ + + - stream object to use during copy. In addition to the types supported in {ref}`method-__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. + #### Returns - **out**: _<array>_ - - an array with the same data and dtype, located on the specified device. + - an array with the same data and data type as `self` and located on the specified `device`. + +```{note} +If `stream` is given, the copy operation should be enqueued on the provided `stream`; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. +``` diff --git a/spec/design_topics/device_support.md b/spec/design_topics/device_support.md index 033e0b3a1..454171731 100644 --- a/spec/design_topics/device_support.md +++ b/spec/design_topics/device_support.md @@ -48,13 +48,22 @@ cross-device data transfer: libraries is out of scope). 2. A `device=None` keyword for array creation functions, which takes an instance of a `Device` object. -3. A `.to_device(device)` method on the array object, with `device` again being - a `Device` object, to move an array to a different device. +3. A `.to_device` method on the array object to copy an array to a different device. ```{note} -The only way to obtain a `Device` object is from the `.device` property on -the array object, hence there is no `Device` object in the array API itself -that can be instantiated to point to a specific physical or logical device. +In the current API standard, the only way to obtain a `Device` object is from the +`.device` property on the array object. The standard does **not** include a universal +`Device` object recognized by all compliant libraries. Accordingly, the standard does +not provide a means of instantiating a `Device` object to point to a specific physical or +logical device. + +The choice to not include a standardized `Device` object may be revisited in a future revision of this standard. + +For array libraries which concern themselves with multi-device support, including CPU and GPU, +they are free to expose a library-specific device object (e.g., for creating an +array on a particular device). While a library-specific device object can be used as input to +`to_device`, beware that this will mean non-portability as code will be specific to +that library. ``` From 996111c8b82e8955db7131e73e2416360a3080d8 Mon Sep 17 00:00:00 2001 From: Lezcano Date: Mon, 1 Nov 2021 19:54:06 +0000 Subject: [PATCH 081/551] Make the writing of the factorisations in linalg more uniform (#220) * Added explicit formulae for the factorisations Added properties of the returned matrices in the main description and the return section Uniform: Always say "(or a stack of matrices)" rather than repeating the properties of the matrices. E.g. Do not write "a square matrix (or a stack of square matrices)" but simply "a square matrix (or stack of matrices)" Uniform: Prefer "Returns" over "Computes" at the start of every description. Uniform: Prefer "decomposition" over "factorization" * Remove backticks from equations The presentation of equations will be fixed in a follow-up PR including TeX rendering support. * Add qualifier * Update copy * Remove line break * Add qualifiers Co-authored-by: Athan --- spec/extensions/linear_algebra_functions.md | 46 +++++++++++---------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 15a2e7efe..e0d3d1f41 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -78,7 +78,7 @@ Accordingly, the standardization process affords the opportunity to reduce inter (function-linalg-cholesky)= ### linalg.cholesky(x, /, *, upper=False) -Returns the Cholesky decomposition of a symmetric positive-definite matrix (or a stack of symmetric positive-definite matrices) `x`. +Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symmetric positive-definite matrix (or a stack of matrices) `x`, where `L` is a lower-triangular matrix or a stack of matrices (`U` is an upper-triangular matrix or a stack of matrices). @@ -90,13 +90,13 @@ Returns the Cholesky decomposition of a symmetric positive-definite matrix (or a - **upper**: _bool_ - - If `True`, the result must be the upper-triangular Cholesky factor. If `False`, the result must be the lower-triangular Cholesky factor. Default: `False`. + - If `True`, the result must be the upper-triangular Cholesky factor `U`. If `False`, the result must be the lower-triangular Cholesky factor `L`. Default: `False`. #### Returns - **out**: _<array>_ - - an array containing the Cholesky factors for each square matrix. The returned array must have a floating-point data type determined by {ref}`type-promotion` and shape as `x`. + - an array containing the Cholesky factors for each square matrix. If `upper` is `False`, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have the same shape as `x`. (function-linalg-cross)= ### linalg.cross(x1, x2, /, *, axis=-1) @@ -126,7 +126,7 @@ Returns the cross product of 3-element vectors. If `x1` and `x2` are multi-dimen (function-linalg-det)= ### linalg.det(x, /) -Returns the determinant of a square matrix (or stack of square matrices) `x`. +Returns the determinant of a square matrix (or a stack of square matrices) `x`. #### Parameters @@ -170,9 +170,9 @@ Returns the specified diagonals of a matrix (or a stack of matrices) `x`. (function-linalg-eigh)= ### linalg.eigh(x, /) -Returns the eigenvalues and eigenvectors of a symmetric matrix (or a stack of symmetric matrices) `x`. +Returns the eigenvalues and eigenvectors x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) `x`, where `Q` is an orthogonal matrix (or a stack of matrices) and `L` is a vector (or a stack of vectors). - + #### Parameters @@ -186,8 +186,8 @@ Returns the eigenvalues and eigenvectors of a symmetric matrix (or a stack of sy - a namedtuple (`eigenvalues`, `eigenvectors`) whose - - first element must have the field name `eigenvalues` and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape `(..., M)`. - - second element have have the field name `eigenvectors` and must be an array where the columns of the inner most matrices contain the computed eigenvectors. The array containing the eigenvectors must have shape `(..., M, M)`. + - first element must have the field name `eigenvalues` (corresponding to `L` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape `(..., M)`. + - second element have have the field name `eigenvectors` (corresponding to `Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape `(..., M, M)`. Each returned array must have the same floating-point data type as `x`. @@ -204,7 +204,7 @@ as it requires complex number support. (function-linalg-eigvalsh)= ### linalg.eigvalsh(x, /) -Computes the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) `x`. +Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) `x`. @@ -233,7 +233,7 @@ as it requires complex number support. (function-linalg-inv)= ### linalg.inv(x, /) -Computes the multiplicative inverse of a square matrix (or a stack of square matrices) `x`. +Returns the multiplicative inverse of a square matrix (or a stack of square matrices) `x`. #### Parameters @@ -327,7 +327,7 @@ Raises a square matrix (or a stack of square matrices) `x` to an integer power ` (function-linalg-matrix_rank)= ### linalg.matrix_rank(x, /, *, rtol=None) -Computes the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). +Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). #### Parameters @@ -353,7 +353,7 @@ Alias for {ref}`function-matrix-transpose`. (function-linalg-outer)= ### linalg.outer(x1, x2, /) -Computes the outer product of two vectors `x1` and `x2`. +Returns the outer product of two vectors `x1` and `x2`. #### Parameters @@ -374,7 +374,7 @@ Computes the outer product of two vectors `x1` and `x2`. (function-linalg-pinv)= ### linalg.pinv(x, /, *, rtol=None) -Computes the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of square matrices) `x`. +Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) `x`. #### Parameters @@ -395,7 +395,7 @@ Computes the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of square ma (function-linalg-qr)= ### linalg.qr(x, /, *, mode='reduced') -Computes the qr factorization of a matrix (or a stack of matrices), where `q` is an orthonormal matrix (or a stack of matrices) and `r` is an upper-triangular matrix (or a stack of matrices). +Returns the qr decomposition x = QR of a matrix (or a stack of matrices) `x`, where `Q` is an orthonormal matrix (or a stack of matrices) and `R` is an upper-triangular matrix (or a stack of matrices). #### Parameters @@ -405,7 +405,7 @@ Computes the qr factorization of a matrix (or a stack of matrices), where `q` is - **mode**: _Literal\[ 'reduced', 'complete' ]_ - - factorization mode. Should be one of the following modes: + - decomposition mode. Should be one of the following modes: - `'reduced'`: compute only the leading `K` columns of `q`, such that `q` and `r` have dimensions `(..., M, K)` and `(..., K, N)`, respectively, and where `K = min(M, N)`. - `'complete'`: compute `q` and `r` with dimensions `(..., M, M)` and `(..., M, N)`, respectively. @@ -418,7 +418,7 @@ Computes the qr factorization of a matrix (or a stack of matrices), where `q` is - a namedtuple `(q, r)` whose - - first element must have the field name `q` and must be an array whose shape depends on the value of `mode` and contain orthonormal matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. + - first element must have the field name `q` and must be an array whose shape depends on the value of `mode` and contain matrices with orthonormal columns. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input array `x`. - second element must have the field name `r` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. Each returned array must have a floating-point data type determined by {ref}`type-promotion`. @@ -476,7 +476,7 @@ Returns the solution to the system of linear equations represented by the well-d (function-linalg-svd)= ### linalg.svd(x, /, *, full_matrices=True) -Computes the singular value decomposition `A = USVh` of a matrix (or a stack of matrices) `x`. +Returns the singular value decomposition A = USVh of a matrix (or a stack of matrices) `x` where `U` is a matrix (or a stack of matrices) with orthonormal columns, `S` is a vector of non-negative numbers (or stack of vectors), and `Vh` is a matrix (or a stack of matrices) with orthonormal rows. #### Parameters @@ -486,24 +486,26 @@ Computes the singular value decomposition `A = USVh` of a matrix (or a stack of - **full_matrices**: _bool_ - - If `True`, compute full-sized `u` and `vh`, such that `u` has shape `(..., M, M)` and `vh` has shape `(..., N, N)`. If `False`, compute on the leading `K` singular vectors, such that `u` has shape `(..., M, K)` and `vh` has shape `(..., K, N)` and where `K = min(M, N)`. Default: `True`. + - If `True`, compute full-sized `U` and `Vh`, such that `U` has shape `(..., M, M)` and `Vh` has shape `(..., N, N)`. If `False`, compute on the leading `K` singular vectors, such that `U` has shape `(..., M, K)` and `Vh` has shape `(..., K, N)` and where `K = min(M, N)`. Default: `True`. #### Returns -- **out**: _Tuple\[ <array>, <array>, <array> ]_ + + +- **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ - a namedtuple `(u, s, vh)` whose - - first element must have the field name `u` and must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the left singular vectors). The left singular vectors must be stored as columns. If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - first element must have the field name `u` and must be an array whose shape depends on the value of `full_matrices` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - second element must have the field name `s` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - third element must have the field name `vh` and must be an array whose shape depends on the value of `full_matrices` and contain unitary array(s) (i.e., the right singular vectors). The right singular vectors must be stored as rows (i.e., the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - third element must have the field name `vh` and must be an array whose shape depends on the value of `full_matrices` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. Each returned array must have the same floating-point data type as `x`. (function-linalg-svdvals)= ### linalg.svdvals(x, /) -Computes the singular values of a matrix (or a stack of matrices) `x`. +Returns the singular values of a matrix (or a stack of matrices) `x`. #### Parameters From 7d3d8fefbf54159f5245d927d493439454473e26 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 3 Nov 2021 16:43:13 -0700 Subject: [PATCH 082/551] Remove DLPack support from asarray (#301) --- spec/API_specification/creation_functions.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index 6cb52aea0..8228a978a 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -57,12 +57,11 @@ Convert the input to an array. #### Parameters -- **obj**: _Union\[ <array>, bool, int, float, NestedSequence\[ bool | int | float ], SupportsDLPack, SupportsBufferProtocol ]_ +- **obj**: _Union\[ <array>, bool, int, float, NestedSequence\[ bool | int | float ], SupportsBufferProtocol ]_ - - object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting DLPack or the Python buffer protocol. + - object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. :::{tip} - An object supporting DLPack has `__dlpack__` and `__dlpack_device__` methods. An object supporting the buffer protocol can be turned into a memoryview through `memoryview(obj)`. ::: @@ -84,11 +83,11 @@ Convert the input to an array. - **device**: _Optional\[ <device> ]_ - - device on which to place the created array. If `device` is `None` and `x` is either an array or an object supporting DLPack, the output array device must be inferred from `x`. Default: `None`. + - device on which to place the created array. If `device` is `None` and `x` is an array, the output array device must be inferred from `x`. Default: `None`. - **copy**: _Optional\[ bool ]_ - - boolean indicating whether or not to copy the input. If `True`, the function must always copy. If `False`, the function must never copy for input which supports DLPack or the buffer protocol and must raise a `ValueError` in case a copy would be necessary. If `None`, the function must reuse existing memory buffer if possible and copy otherwise. Default: `None`. + - boolean indicating whether or not to copy the input. If `True`, the function must always copy. If `False`, the function must never copy for input which supports the buffer protocol and must raise a `ValueError` in case a copy would be necessary. If `None`, the function must reuse existing memory buffer if possible and copy otherwise. Default: `None`. #### Returns @@ -96,7 +95,6 @@ Convert the input to an array. - an array containing the data from `obj`. - (function-empty)= ### empty(shape, *, dtype=None, device=None) From 84605523d2b291e88f5c427bda3256f8ac95b467 Mon Sep 17 00:00:00 2001 From: Lezcano Date: Thu, 4 Nov 2021 00:40:56 +0000 Subject: [PATCH 083/551] Account for when factorizations may not be well-defined (#224) Co-authored-by: Athan --- spec/extensions/linear_algebra_functions.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index e0d3d1f41..d9b860aa7 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -170,7 +170,7 @@ Returns the specified diagonals of a matrix (or a stack of matrices) `x`. (function-linalg-eigh)= ### linalg.eigh(x, /) -Returns the eigenvalues and eigenvectors x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) `x`, where `Q` is an orthogonal matrix (or a stack of matrices) and `L` is a vector (or a stack of vectors). +Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) `x`, where `Q` is an orthogonal matrix (or a stack of matrices) and `L` is a vector (or a stack of vectors). @@ -192,7 +192,6 @@ Returns the eigenvalues and eigenvectors x = QLQᵀ of a symmetric matrix (or a Each returned array must have the same floating-point data type as `x`. ```{note} - Eigenvalue sort order is left unspecified. ``` @@ -221,7 +220,6 @@ Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) - an array containing the computed eigenvalues. The returned array must have shape `(..., M)` and have the same data type as `x`. ```{note} - Eigenvalue sort order is left unspecified. ``` @@ -395,13 +393,13 @@ Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) (function-linalg-qr)= ### linalg.qr(x, /, *, mode='reduced') -Returns the qr decomposition x = QR of a matrix (or a stack of matrices) `x`, where `Q` is an orthonormal matrix (or a stack of matrices) and `R` is an upper-triangular matrix (or a stack of matrices). +Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where `Q` is an orthonormal matrix (or a stack of matrices) and `R` is an upper-triangular matrix (or a stack of matrices). #### Parameters - **x**: _<array>_ - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices of rank equal to `N`. Should have a floating-point data type. - **mode**: _Literal\[ 'reduced', 'complete' ]_ @@ -429,7 +427,6 @@ Returns the qr decomposition x = QR of a matrix (or a stack of matrices) `x`, wh Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) `x`. ```{note} - The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling `det` may overflow or underflow. ``` @@ -476,7 +473,7 @@ Returns the solution to the system of linear equations represented by the well-d (function-linalg-svd)= ### linalg.svd(x, /, *, full_matrices=True) -Returns the singular value decomposition A = USVh of a matrix (or a stack of matrices) `x` where `U` is a matrix (or a stack of matrices) with orthonormal columns, `S` is a vector of non-negative numbers (or stack of vectors), and `Vh` is a matrix (or a stack of matrices) with orthonormal rows. +Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) `x`, where `U` is a matrix (or a stack of matrices) with orthonormal columns, `S` is a vector of non-negative numbers (or stack of vectors), and `Vh` is a matrix (or a stack of matrices) with orthonormal rows. #### Parameters From 64c4c585e8005a86673e9f53e36c8dac3d0c2b96 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 3 Nov 2021 18:09:48 -0700 Subject: [PATCH 084/551] Add notes concerning input array validation (#302) --- spec/extensions/linear_algebra_functions.md | 40 +++++++++++++++------ 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index d9b860aa7..4f4a62b22 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -82,6 +82,10 @@ Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symm +```{note} +Whether an array library explicitly checks whether an input array is a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. +``` + #### Parameters - **x**: _<array>_ @@ -170,10 +174,18 @@ Returns the specified diagonals of a matrix (or a stack of matrices) `x`. (function-linalg-eigh)= ### linalg.eigh(x, /) +```{note} +The function `eig` will be added in a future version of the specification, as it requires complex number support. +``` + Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) `x`, where `Q` is an orthogonal matrix (or a stack of matrices) and `L` is a vector (or a stack of vectors). +```{note} +Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. +``` + #### Parameters - **x**: _<array>_ @@ -195,18 +207,21 @@ Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of sy Eigenvalue sort order is left unspecified. ``` -```{note} -The function `eig` will be added in a future version of the specification, -as it requires complex number support. -``` - (function-linalg-eigvalsh)= ### linalg.eigvalsh(x, /) +```{note} +The function `eigvals` will be added in a future version of the specification, as it requires complex number support. +``` + Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) `x`. +```{note} +Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. +``` + #### Parameters - **x**: _<array>_ @@ -223,11 +238,6 @@ Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) Eigenvalue sort order is left unspecified. ``` -```{note} -The function `eigvals` will be added in a future version of the specification, -as it requires complex number support. -``` - (function-linalg-inv)= ### linalg.inv(x, /) @@ -395,11 +405,15 @@ Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where `Q` is an orthonormal matrix (or a stack of matrices) and `R` is an upper-triangular matrix (or a stack of matrices). +```{note} +Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. +``` + #### Parameters - **x**: _<array>_ - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices of rank equal to `N`. Should have a floating-point data type. + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices of rank `N`. Should have a floating-point data type. - **mode**: _Literal\[ 'reduced', 'complete' ]_ @@ -454,6 +468,10 @@ The purpose of this function is to calculate the determinant more accurately whe Returns the solution to the system of linear equations represented by the well-determined (i.e., full rank) linear matrix equation `AX = B`. +```{note} +Whether an array library explicitly checks whether an input array is full rank is implementation-defined. +``` + #### Parameters - **x1**: _<array>_ From 52905bfc6d7475f531d837e567380e358a2d0d2d Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 3 Nov 2021 19:13:00 -0700 Subject: [PATCH 085/551] Update guidance for linalg `rtol` tolerance cutoff to accommodate non-SVD algorithms (#304) For further discussion, see https://github.com/data-apis/array-api/issues/216 --- spec/extensions/linear_algebra_functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 4f4a62b22..90e21d9a4 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -345,7 +345,7 @@ Returns the rank (i.e., number of non-zero singular values) of a matrix (or a st - **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - relative tolerance for small singular values. Singular values less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. + - relative tolerance for small singular values. Singular values approximately less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. #### Returns @@ -392,7 +392,7 @@ Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) - **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - relative tolerance for small singular values. Singular values less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. + - relative tolerance for small singular values. Singular values approximately less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. #### Returns From 8768cbbc22a1adecc789580561453b1f3631042d Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 3 Nov 2021 19:17:40 -0700 Subject: [PATCH 086/551] Move guidance to note and allow for errors in approximation (#303) --- spec/extensions/linear_algebra_functions.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 90e21d9a4..a2d53d9a6 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -459,10 +459,14 @@ The purpose of this function is to calculate the determinant more accurately whe - first element must have the field name `sign` and must be an array containing a number representing the sign of the determinant for each square matrix. - second element must have the field name `logabsdet` and must be an array containing the determinant for each square matrix. - For a real matrix, the sign of the determinant must be either `1`, `0`, or `-1`. If a determinant is zero, then the corresponding `sign` must be `0` and `logabsdet` must be `-infinity`. In all cases, the determinant must be equal to `sign * exp(logsabsdet)`. + For a real matrix, the sign of the determinant must be either `1`, `0`, or `-1`. Each returned array must have shape `shape(x)[:-2]` and a floating-point data type determined by {ref}`type-promotion`. + ```{note} + If a determinant is zero, then the corresponding `sign` should be `0` and `logabsdet` should be `-infinity`; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to `sign * exp(logsabsdet)` (although, again, the result may be subject to numerical precision errors). + ``` + (function-linalg-solve)= ### linalg.solve(x1, x2, /) From 7c98b00d7cb39ff9b2c00d0c8ec743695fbaad73 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 4 Nov 2021 05:13:01 +0000 Subject: [PATCH 087/551] Arrays must share the same dtype in `meshgrid()` (#298) * Modify `meshgrid()` so arrays must share the same dtype * must -> should for dtype behaviour in `meshgrid()` --- spec/API_specification/creation_functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md index 8228a978a..a4b4e7d99 100644 --- a/spec/API_specification/creation_functions.md +++ b/spec/API_specification/creation_functions.md @@ -320,7 +320,7 @@ Returns coordinate matrices from coordinate vectors. - **arrays**: _<array>_ - - an arbitrary number of one-dimensional arrays representing grid coordinates. Must have numeric data types. + - an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - **indexing**: _str_ @@ -340,7 +340,7 @@ Returns coordinate matrices from coordinate vectors. Similarly, for the three-dimensional case with input one-dimensional arrays of length `M`, `N`, and `P`, if matrix indexing `ij`, then each returned array must have shape `(M, N, P)`, and, if Cartesian indexing `xy`, then each returned array must have shape `(N, M, P)`. - The returned arrays must have a numeric data type determined by {ref}`type-promotion`. + Each returned array should have the same data type as the input arrays. (function-ones)= ### ones(shape, *, dtype=None, device=None) From 4294f438951b87b204265390c6f422da9db1213a Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 4 Nov 2021 05:18:00 +0000 Subject: [PATCH 088/551] Require in-place operations match binary operation equivalents (#299) * Clarify in-place operations mirror special case behaviour * Clarify that in-place ops follow all functionality of standard ops * Update copy Co-authored-by: Athan --- spec/API_specification/array_object.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index ff5b1b46b..31b8a84ab 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -156,6 +156,11 @@ an array object supporting the following in-place Python operators: An in-place operation must not change the dtype or shape of the in-place array as a result of {ref}`type-promotion` or {ref}`broadcasting`. +An in-place operation must have the same behavior (including special cases) as +its respective binary (i.e., two operand, non-assignment) operation. For example, +after in-place addition `x1 += x2`, the modified array `x1` must always equal the +result of the equivalent binary arithmetic operation `x1 = x1 + x2`. + ```{note} In-place operators must be supported as discussed in {ref}`copyview-mutability`. From 45771c998ec52fa4d4c0e1aa35c53757970f6865 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 4 Nov 2021 08:13:49 +0000 Subject: [PATCH 089/551] Include entry points as an optional feature (#297) * Entry points as an optional feature when adoption * Update copy * Fix grammar * Revert change * Update copy Co-authored-by: Athan --- spec/conf.py | 1 + spec/purpose_and_scope.md | 25 +++++++++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/spec/conf.py b/spec/conf.py index 308ba52d2..ffb1e94a2 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -143,4 +143,5 @@ ), "durole": ("http://docutils.sourceforge.net/docs/ref/rst/" "roles.html#%s", ""), "dudir": ("http://docutils.sourceforge.net/docs/ref/rst/" "directives.html#%s", ""), + "pypa": ("https://packaging.python.org/%s", ""), } diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index 56046a277..3ef3bc611 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -369,6 +369,31 @@ recommended not to add other functions or objects, because that may make it harder for users to write code that will work with multiple array libraries. +### Discoverability + +To assist array-consuming libraries which need to create arrays originating from multiple conforming array implementations, conforming implementations may provide an {pypa}`entry point ` in order to make an array API namespace discoverable. For example, + +```python +from importlib.metadata import entry_points + +try: + eps = entry_points()['array_api'] + ep = next(ep for ep in eps if ep.name == 'package_name') +except TypeError: + # The dict interface for entry_points() is deprecated in py3.10, + # supplanted by a new select interface. + ep = entry_points(group='array_api', name='package_name') + +xp = ep.load() +``` + +An entry point must have the following properties: + +- **group**: equal to `array_api`. +- **name**: equal to the package name. +- **object reference**: equal to the array API namespace import path. + + * * * ## Conformance From 69430af1ad5ab9687ba5edab62b2b63164576080 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 01:32:14 -0700 Subject: [PATCH 090/551] Remove note in adoption guidance (#306) --- spec/purpose_and_scope.md | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index 3ef3bc611..a3a7d0210 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -349,24 +349,10 @@ request a specific API version: xp = x.__array_namespace__(api_version='2020.10') ``` -```{note} - -This is inspired by [NEP 37](https://numpy.org/neps/nep-0037-array-module.html#how-to-use-get-array-module), -however it avoids adding a dependency on NumPy or having to provide a -separate package just to do `get_array_module(x)` - -NEP 37 is still in flux (it was just accepted by JAX and TensorFlow on an -experimental basis), and it's possible that that should be accepted instead. - -TBD: a decision must be made on this topic before a first version of the -standard can become final. We prefer to delay this decision, to see how -NEP 37 adoption will work out. -``` - The `xp` namespace must contain all functionality specified in -{ref}`api-specification`. It may contain other functionality, however it is -recommended not to add other functions or objects, because that may make it -harder for users to write code that will work with multiple array libraries. +{ref}`api-specification`. The namespace may contain other functionality; however, +including additional functionality is not recommended as doing so may hinder +portability and inter-operation of array libraries within user code. ### Discoverability From 2b97674019e2c614e37634ad4c404d380989ac04 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 02:10:12 -0700 Subject: [PATCH 091/551] Disallow scalar operands when using the matmul operator (#307) --- spec/API_specification/type_promotion.md | 50 ++++++++---------------- 1 file changed, 17 insertions(+), 33 deletions(-) diff --git a/spec/API_specification/type_promotion.md b/spec/API_specification/type_promotion.md index ae1faac44..d8aedde42 100644 --- a/spec/API_specification/type_promotion.md +++ b/spec/API_specification/type_promotion.md @@ -4,8 +4,7 @@ > Array API specification for type promotion rules. -Type promotion rules can be understood at a high level from the following -diagram: +Type promotion rules can be understood at a high level from the following diagram: ![Type promotion diagram](/_static/images/dtype_promotion_lattice.png) @@ -19,17 +18,12 @@ A conforming implementation of the array API standard must implement the followi A conforming implementation of the array API standard may support additional type promotion rules beyond those described in this specification. ```{note} - -Type codes are used here to keep tables readable; they are not part of the standard. -In code, use the data type objects specified in {ref}`data-types` (e.g., `int16` rather than `'i2'`). +Type codes are used here to keep tables readable; they are not part of the standard. In code, use the data type objects specified in {ref}`data-types` (e.g., `int16` rather than `'i2'`). ``` -The following type promotion tables specify the casting behavior for -operations involving two array operands. When more than two array operands -participate, application of the promotion tables is associative (i.e., the -result does not depend on operand order). +The following type promotion tables specify the casting behavior for operations involving two array operands. When more than two array operands participate, application of the promotion tables is associative (i.e., the result does not depend on operand order). ### Signed integer type promotion table @@ -90,39 +84,29 @@ where - Type promotion of non-numerical data types to numerical data types is unspecified (e.g., `bool` to `intxx` or `floatxx`). ```{note} - -Mixed integer and floating-point type promotion rules are not specified -because behavior varies between implementations. +Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. ``` ### Mixing arrays with Python scalars -Using Python scalars (i.e., instances of `bool`, `int`, `float`) together with -arrays must be supported for: +Using Python scalars (i.e., instances of `bool`, `int`, `float`) together with arrays must be supported for: -- `array scalar` -- `scalar array` +- `array scalar` +- `scalar array` -where `` is a built-in operator, including in-place operators (see -{ref}`operators` for operators supported by the array object) and `scalar` has -a compatible type and value to the array dtype: -- Python `bool` for a `bool` array dtype, -- a Python `int` within the [bounds](data-types) of the given dtype for integer array dtypes, -- a Python `int` or `float` for floating-point array dtypes +where `` is a built-in operator (including in-place operators, but excluding the matmul `@` operator; see {ref}`operators` for operators supported by the array object) and `scalar` has a type and value compatible with the array data type: -The expected behavior is then equivalent to: +- a Python `bool` for a `bool` array data type. +- a Python `int` within the [bounds](data-types) of the given data type for integer array data types. +- a Python `int` or `float` for floating-point array data types. -1. Convert the scalar to a 0-D array with the same dtype as that of the array - used in the expression. -2. Execute the operation for `array 0-D array` (or `0-D array - array` if `scalar` was the left-hand argument). +Provided the above requirements are met, the expected behavior is equivalent to: -```{note} +1. Convert the scalar to zero-dimensional array with the same data type as that of the array used in the expression. +2. Execute the operation for `array 0-D array` (or `0-D array array` if `scalar` was the left-hand argument). -Behaviour is not specified when mixing a Python `float` and an array with an -integer dtype; this may give `float32`, `float64`, or raise an exception - -behavior of implementations will differ. +```{note} +Behavior is not specified when mixing a Python `float` and an array with an integer data type; this may give `float32`, `float64`, or raise an exception. Behavior is implementation-specific. -The behavior is also not specified for integers outside of the bounds of a -given integer dtype. It may overflow, or result in an error. +The behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. ``` From 2e17ca1f3cefaef0af7aedfa1ca966ff410574e1 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 02:42:07 -0700 Subject: [PATCH 092/551] Group operators into separate classes (#308) * Group operators * Fix placement --- spec/API_specification/array_object.md | 172 +++++++++++++++---------- 1 file changed, 102 insertions(+), 70 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 31b8a84ab..2f4fe7e99 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -19,37 +19,11 @@ A conforming implementation of the array API standard must provide and support a ## Operators -A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators: +A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. -- `x1 < x2`: [`__lt__(x1, x2)`](#__lt__self-other-) - - - [`operator.lt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.lt) - - [`operator.__lt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__lt__) +### Arithmetic Operators -- `x1 <= x2`: [`__le__(x1, x2)`](#__le__self-other-) - - - [`operator.le(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.le) - - [`operator.__le__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__le__) - -- `x1 > x2`: [`__gt__(x1, x2)`](#__gt__self-other-) - - - [`operator.gt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.gt) - - [`operator.__gt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__gt__) - -- `x1 >= x2`: [`__ge__(x1, x2)`](#__ge__self-other-) - - - [`operator.ge(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ge) - - [`operator.__ge__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ge__) - -- `x1 == x2`: [`__eq__(x1, x2)`](#__eq__self-other-) - - - [`operator.eq(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.eq) - - [`operator.__eq__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__eq__) - -- `x1 != x2`: [`__ne__(x1, x2)`](#__ne__self-other-) - - - [`operator.ne(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ne) - - [`operator.__ne__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ne__) +A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. - `+x`: [`__pos__(x)`](#__pos__self-) @@ -96,11 +70,23 @@ A conforming implementation of the array API standard must provide and support a - [`operator.pow(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.pow) - [`operator.__pow__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__pow__) +Arithmetic operators should be defined for arrays having numeric data types. + +### Array Operators + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. + - `x1 @ x2`: [`__matmul__(x1, x2)`](#__matmul__self-other-) - [`operator.matmul(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.matmul) - [`operator.__matmul__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__matmul__) +The matmul `@` operator should be defined for arrays having numeric data types. + +### Bitwise Operators + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. + - `~x`: [`__invert__(x)`](#__invert__self-) - [`operator.inv(x)`](https://docs.python.org/3/library/operator.html#operator.inv) @@ -133,57 +119,81 @@ A conforming implementation of the array API standard must provide and support a - [`operator.rshift(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.rshift) - [`operator.__rshift__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__rshift__) +Bitwise operators should be defined for arrays having integer and boolean data types. + +### Comparison Operators + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. + +- `x1 < x2`: [`__lt__(x1, x2)`](#__lt__self-other-) + + - [`operator.lt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.lt) + - [`operator.__lt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__lt__) + +- `x1 <= x2`: [`__le__(x1, x2)`](#__le__self-other-) + + - [`operator.le(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.le) + - [`operator.__le__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__le__) + +- `x1 > x2`: [`__gt__(x1, x2)`](#__gt__self-other-) + + - [`operator.gt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.gt) + - [`operator.__gt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__gt__) + +- `x1 >= x2`: [`__ge__(x1, x2)`](#__ge__self-other-) + + - [`operator.ge(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ge) + - [`operator.__ge__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ge__) + +- `x1 == x2`: [`__eq__(x1, x2)`](#__eq__self-other-) + + - [`operator.eq(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.eq) + - [`operator.__eq__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__eq__) + +- `x1 != x2`: [`__ne__(x1, x2)`](#__ne__self-other-) + + - [`operator.ne(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ne) + - [`operator.__ne__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ne__) + +Comparison operators should be defined for arrays having any data type. ### In-place Operators -A conforming implementation of the array API standard must provide and support -an array object supporting the following in-place Python operators: - -- `+=`. May be implemented via `__iadd__`. -- `-=`. May be implemented via `__isub__`. -- `*=`. May be implemented via `__imul__`. -- `/=`. May be implemented via `__itruediv__`. -- `//=`. May be implemented via `__ifloordiv__`. -- `**=`. May be implemented via `__ipow__`. -- `@=`. May be implemented via `__imatmul__`. -- `%=`. May be implemented via `__imod__`. -- `&=`. May be implemented via `__iand__`. -- `|=`. May be implemented via `__ior__`. -- `^=`. May be implemented via `__ixor__`. -- `<<=`. May be implemented via `__ilshift__`. -- `>>=`. May be implemented via `__irshift__`. - -An in-place operation must not change the dtype or shape of the in-place array -as a result of {ref}`type-promotion` or {ref}`broadcasting`. - -An in-place operation must have the same behavior (including special cases) as -its respective binary (i.e., two operand, non-assignment) operation. For example, -after in-place addition `x1 += x2`, the modified array `x1` must always equal the -result of the equivalent binary arithmetic operation `x1 = x1 + x2`. +A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. -```{note} +An in-place operation must not change the data type or shape of the in-place array as a result of {ref}`type-promotion` or {ref}`broadcasting`. + +An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition `x1 += x2`, the modified array `x1` must always equal the result of the equivalent binary arithmetic operation `x1 = x1 + x2`. +```{note} In-place operators must be supported as discussed in {ref}`copyview-mutability`. ``` +#### Arithmetic Operators + +- `+=`. May be implemented via `__iadd__`. +- `-=`. May be implemented via `__isub__`. +- `*=`. May be implemented via `__imul__`. +- `/=`. May be implemented via `__itruediv__`. +- `//=`. May be implemented via `__ifloordiv__`. +- `**=`. May be implemented via `__ipow__`. +- `%=`. May be implemented via `__imod__`. + +#### Array Operators + +- `@=`. May be implemented via `__imatmul__`. + +#### Bitwise Operators + +- `&=`. May be implemented via `__iand__`. +- `|=`. May be implemented via `__ior__`. +- `^=`. May be implemented via `__ixor__`. +- `<<=`. May be implemented via `__ilshift__`. +- `>>=`. May be implemented via `__irshift__`. + ### Reflected Operators -A conforming implementation of the array API standard must provide and support -an array object supporting the following reflected operators: - -- `__radd__` -- `__rsub__` -- `__rmul__` -- `__rtruediv__` -- `__rfloordiv__` -- `__rpow__` -- `__rmatmul__` -- `__rmod__` -- `__rand__` -- `__ror__` -- `__rxor__` -- `__rlshift__` -- `__rrshift__` +A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. The results of applying reflected operators must match their non-reflected equivalents. @@ -191,6 +201,28 @@ The results of applying reflected operators must match their non-reflected equiv All operators for which `array scalar` is implemented must have an equivalent reflected operator implementation. ``` +#### Arithmetic Operators + +- `__radd__` +- `__rsub__` +- `__rmul__` +- `__rtruediv__` +- `__rfloordiv__` +- `__rpow__` +- `__rmod__` + +#### Array Operators + +- `__rmatmul__` + +#### Bitwise Operators + +- `__rand__` +- `__ror__` +- `__rxor__` +- `__rlshift__` +- `__rrshift__` + * * * ## Attributes From d7df6aebef5b2b90a5a723f6bbf86a657f0aeaa6 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 03:26:25 -0700 Subject: [PATCH 093/551] Add guidance concerning how to check for an array API compliant object (#309) --- spec/purpose_and_scope.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index a3a7d0210..a7324c2e8 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -354,6 +354,20 @@ The `xp` namespace must contain all functionality specified in including additional functionality is not recommended as doing so may hinder portability and inter-operation of array libraries within user code. +### Checking for Compliance + +Array-consuming libraries are likely to want a mechanism for determining whether a provided array is specification compliant. The recommended approach to check for compliance is by checking whether an array object has an `__array_namespace__` attribute, as this is the one distinguishing feature of an array-compliant object. + +Checking for an `__array_namespace__` attribute can be implemented as a small utility function similar to the following. + +```python +def is_array_api_obj(x): + return hasattr(x, '__array_namespace__') +``` + +```{note} +Providing a "reference library" on which people depend is out-of-scope; hence, the standard cannot, e.g., provide an array ABC from which libraries can inherit to enable an `isinstance` check. +``` ### Discoverability From e3e1a46a405a73901a7dfb7a800d741267d3a55d Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 04:13:02 -0700 Subject: [PATCH 094/551] Require that NaNs be considered distinct when returning unique elements (#310) * Require that NaNs be considered distinct * Update copy --- spec/API_specification/set_functions.md | 31 +++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/set_functions.md b/spec/API_specification/set_functions.md index 3f3a9d192..74408b0b1 100644 --- a/spec/API_specification/set_functions.md +++ b/spec/API_specification/set_functions.md @@ -23,6 +23,17 @@ The shapes of two of the output arrays for this function depend on the data valu Returns the unique elements of an input array `x`. +```{note} +Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. + +- As `nan` values compare as `False`, `nan` values should be considered distinct. +- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). + +As signed zeros are not distinct, using `inverse_indices` to reconstruct the input array is not guaranteed to return an array having the exact same values. + +Each `nan` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. +``` + #### Parameters - **x**: _<array>_ @@ -47,14 +58,23 @@ Returns the unique elements of an input array `x`. (function-unique-inverse)= ### unique_inverse(x, /) -Returns the unique elements of an input array `x` and the indices from the set of unique elements that reconstruct `x`. - :::{admonition} Data-dependent output shape :class: important The shape of one of the output arrays for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. ::: +Returns the unique elements of an input array `x` and the indices from the set of unique elements that reconstruct `x`. + +```{note} +Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. + +- As `nan` values compare as `False`, `nan` values should be considered distinct. +- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). + +As signed zeros are not distinct, using `inverse_indices` to reconstruct the input array is not guaranteed to return an array having the exact same values. +``` + #### Parameters - **x**: _<array>_ @@ -85,6 +105,13 @@ The shape of the output array for this function depends on the data values in th Returns the unique elements of an input array `x`. +```{note} +Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. + +- As `nan` values compare as `False`, `nan` values should be considered distinct. +- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). +``` + #### Parameters - **x**: _<array>_ From 654d58da570d7c7c7ffbf3f7835cfd37af77e0e6 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 21:08:13 -0700 Subject: [PATCH 095/551] Specify shape behavior (#289) * Specify shape behavior * Update copy * Update guidance to remove support for arrays of unknown rank * Update copy --- spec/API_specification/array_object.md | 33 +++++++++++++++----------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 2f4fe7e99..e496f99ee 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -275,8 +275,6 @@ Number of array dimensions (axes). - number of array dimensions (axes). -_TODO: need to more carefully consider this in order to accommodate, e.g., graph tensors where the number of dimensions may be dynamic._ - (attribute-shape)= ### shape @@ -284,24 +282,36 @@ Array dimensions. #### Returns -- **out**: _Union\[ Tuple\[ int, ...], <shape> ]_ +- **out**: _Tuple\[ Optional\[ int ], ... ]_ - - array dimensions as either a tuple or a custom shape object. If a shape object, the object must be immutable and must support indexing for dimension retrieval. + - array dimensions. An array dimension must be `None` if and only if a dimension is unknown. -_TODO: need to more carefully consider this in order to accommodate, e.g., graph tensors where a shape may be dynamic._ +```{note} +For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; `A[:, B > 0]`) and thus cannot be statically resolved without knowing array contents. +``` + +```{note} +The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. +``` (attribute-size)= ### size -Number of elements in an array. This must equal the product of the array's dimensions. +Number of elements in an array. + +```{note} +This must equal the product of the array's dimensions. +``` #### Returns -- **out**: _int_ +- **out**: _Optional\[ int ]_ - - number of elements in an array. + - number of elements in an array. The returned value must be `None` if and only if one or more array dimensions are unknown. -_TODO: need to more carefully consider this in order to accommodate, e.g., graph tensors where the number of elements may be dynamic._ +```{note} +For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. +``` (attribute-T)= ### T @@ -783,11 +793,6 @@ Computes the truth value of `self_i <= other_i` for each element of an array ins Element-wise results must equal the results returned by the equivalent element-wise function [`less_equal(x1, x2)`](elementwise_functions.md#less_equalx1-x2-). ``` -(method-__len__)= -### \_\_len\_\_(self, /) - -_TODO: need to more carefully consider this in order to accommodate, e.g., graph tensors where a shape may be dynamic. Furthermore, not clear whether this should be implemented, as, e.g., NumPy's behavior of returning the size of the first dimension is not necessarily intuitive, as opposed to, say, the total number of elements._ - (method-__lshift__)= ### \_\_lshift\_\_(self, other, /) From c08d302ad7a32cd2923d9be3cafa08429d7eb5db Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 21:23:22 -0700 Subject: [PATCH 096/551] Update namedtuple field names for `linalg.qr` and `linalg.svd` (#313) --- spec/extensions/linear_algebra_functions.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index a2d53d9a6..4e3dbe311 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -204,7 +204,7 @@ Whether an array library explicitly checks whether an input array is a symmetric Each returned array must have the same floating-point data type as `x`. ```{note} -Eigenvalue sort order is left unspecified. +Eigenvalue sort order is left unspecified and is thus implementation-dependent. ``` (function-linalg-eigvalsh)= @@ -235,7 +235,7 @@ Whether an array library explicitly checks whether an input array is a symmetric - an array containing the computed eigenvalues. The returned array must have shape `(..., M)` and have the same data type as `x`. ```{note} -Eigenvalue sort order is left unspecified. +Eigenvalue sort order is left unspecified and is thus implementation-dependent. ``` (function-linalg-inv)= @@ -428,10 +428,10 @@ Whether an array library explicitly checks whether an input array is a full colu - **out**: _Tuple\[ <array>, <array> ]_ - - a namedtuple `(q, r)` whose + - a namedtuple `(Q, R)` whose - - first element must have the field name `q` and must be an array whose shape depends on the value of `mode` and contain matrices with orthonormal columns. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input array `x`. - - second element must have the field name `r` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. + - first element must have the field name `Q` and must be an array whose shape depends on the value of `mode` and contain matrices with orthonormal columns. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input array `x`. + - second element must have the field name `R` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. Each returned array must have a floating-point data type determined by {ref}`type-promotion`. @@ -513,11 +513,11 @@ Returns a singular value decomposition A = USVh of a matrix (or a stack of matri - **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ - - a namedtuple `(u, s, vh)` whose + - a namedtuple `(U, S, Vh)` whose - - first element must have the field name `u` and must be an array whose shape depends on the value of `full_matrices` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - second element must have the field name `s` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - third element must have the field name `vh` and must be an array whose shape depends on the value of `full_matrices` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - first element must have the field name `U` and must be an array whose shape depends on the value of `full_matrices` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - second element must have the field name `S` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - third element must have the field name `Vh` and must be an array whose shape depends on the value of `full_matrices` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. Each returned array must have the same floating-point data type as `x`. From e471e8a00e27cfe6f2aeb3b829eb1d40ea94554d Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 4 Nov 2021 23:20:37 -0600 Subject: [PATCH 097/551] Clarify matmul error conditions and fix linalg docs (#282) * Fix the input description for cholesky() * Add some additional error cases for @ and matmul Also use more consistent variable names for the shapes in the error cases. * Fix the output shape for qr(mode='complete').r * Clarify what K equals in the svd and svdvals specifications * Use consistent naming conventions * Use consistent naming conventions * Use consistent naming conventions * Restore changes Co-authored-by: Athan --- spec/API_specification/array_object.md | 4 +++- spec/API_specification/linear_algebra_functions.md | 4 +++- spec/extensions/linear_algebra_functions.md | 8 ++++---- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index e496f99ee..29687f9e6 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -883,7 +883,9 @@ The `matmul` function must implement the same semantics as the built-in `@` oper #### Raises - if either `self` or `other` is a zero-dimensional array. -- if `self` is a one-dimensional array having shape `(N)`, `other` is a one-dimensional array having shape `(M)`, and `N != M`. +- if `self` is a one-dimensional array having shape `(K)`, `other` is a one-dimensional array having shape `(L)`, and `K != L`. +- if `self` is a one-dimensional array having shape `(K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. +- if `self` is an array having shape `(..., M, K)`, `other` is a one-dimensional array having shape `(L)`, and `K != L`. - if `self` is an array having shape `(..., M, K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. (method-__mod__)= diff --git a/spec/API_specification/linear_algebra_functions.md b/spec/API_specification/linear_algebra_functions.md index 139dea215..66db0d079 100644 --- a/spec/API_specification/linear_algebra_functions.md +++ b/spec/API_specification/linear_algebra_functions.md @@ -52,7 +52,9 @@ The `matmul` function must implement the same semantics as the built-in `@` oper #### Raises - if either `x1` or `x2` is a zero-dimensional array. -- if `x1` is a one-dimensional array having shape `(N)`, `x2` is a one-dimensional array having shape `(M)`, and `N != M`. +- if `x1` is a one-dimensional array having shape `(K)`, `x2` is a one-dimensional array having shape `(L)`, and `K != L`. +- if `x1` is a one-dimensional array having shape `(K)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. +- if `x1` is an array having shape `(..., M, K)`, `x2` is a one-dimensional array having shape `(L)`, and `K != L`. - if `x1` is an array having shape `(..., M, K)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. (function-matrix-transpose)= diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 4e3dbe311..0e432a896 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -90,7 +90,7 @@ Whether an array library explicitly checks whether an input array is a symmetric - **x**: _<array>_ - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + - input array having shape `(..., M, M)` and whose innermost two dimensions form square symmetric positive-definite matrices. Should have a floating-point data type. - **upper**: _bool_ @@ -431,7 +431,7 @@ Whether an array library explicitly checks whether an input array is a full colu - a namedtuple `(Q, R)` whose - first element must have the field name `Q` and must be an array whose shape depends on the value of `mode` and contain matrices with orthonormal columns. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input array `x`. - - second element must have the field name `R` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. + - second element must have the field name `R` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, N)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. Each returned array must have a floating-point data type determined by {ref}`type-promotion`. @@ -516,7 +516,7 @@ Returns a singular value decomposition A = USVh of a matrix (or a stack of matri - a namedtuple `(U, S, Vh)` whose - first element must have the field name `U` and must be an array whose shape depends on the value of `full_matrices` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - second element must have the field name `S` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. + - second element must have the field name `S` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`, where `K = min(M, N)`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - third element must have the field name `Vh` and must be an array whose shape depends on the value of `full_matrices` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. Each returned array must have the same floating-point data type as `x`. @@ -536,7 +536,7 @@ Returns the singular values of a matrix (or a stack of matrices) `x`. - **out**: _<array>_ - - an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. The returned array must have the same floating-point data type as `x`. + - an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`, where `K = min(M, N)`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. The returned array must have the same floating-point data type as `x`. (function-linalg-tensordot)= ### linalg.tensordot(x1, x2, /, *, axes=2) From f4c8c7f884647174e8ba19e2249914e9f894207a Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 4 Nov 2021 22:46:19 -0700 Subject: [PATCH 098/551] Remove obsolete TODOs (#314) --- spec/purpose_and_scope.md | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index a7324c2e8..4bcfb4a7e 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -48,14 +48,6 @@ functionality that's not present in this document?_ This: - may indicate that that functionality, if present in a particular array library, is unlikely to be present in all other libraries -```{note} - -This document is ready for wider community review, but still contains a -number of TODOs, and is expected to change and evolve before a first -official release. See {ref}`future-API-evolution` for proposed -versioning. -``` - ### History The first library for numerical and scientific computing in Python was @@ -117,8 +109,7 @@ Furthermore, meta-topics included in this standard include: - Verification of API standard conformance The concrete set of functionality that is in scope for this version of the -standard is shown in this diagram (_TODO: update after deciding on how optional -extensions are dealt with_): +standard is shown in this diagram: ![Scope of array API](_static/images/scope_of_array_API.png) @@ -217,15 +208,6 @@ extensions are dealt with_): used is best left to the end user._ -### TBD whether or not in scope, or for a later version - -- Random number generation, Fourier transforms, and miscellaneous functionality - like a padding function. - - _This will be decided later, depending on whether "optional extensions" will - be added to the standard._ - - ### Implications of in/out of scope If something is out of scope and therefore will not be part of (the current From aa6c89c47c6f6f37fa0b53934b3c5784985d0628 Mon Sep 17 00:00:00 2001 From: Athan Date: Fri, 5 Nov 2021 08:29:00 -0700 Subject: [PATCH 099/551] Add guidance requiring support for zero-dimensional arrays (#315) --- spec/API_specification/array_object.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 29687f9e6..303ee7a1e 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -13,6 +13,16 @@ A conforming implementation of the array API standard must provide and support a - Unless stated otherwise, methods must adhere to the type promotion rules defined in {ref}`type-promotion`. - Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +Furthermore, a conforming implementation of the array API standard must support array objects of arbitrary rank `N` (i.e., number of dimensions), where `N` is greater than or equal to zero. + +```{note} +Conforming implementations must support zero-dimensional arrays. + +Apart from array object attributes, such as `ndim`, `device`, and `dtype`, all operations in this standard return arrays (or tuples of arrays), including those operations, such as `mean`, `var`, and `std`, from which some common array libraries (e.g., NumPy) return scalar values. + +_Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value._ +``` + * * * (operators)= From 568f81f3b8331bcfb52e36c35f02786d8d56ffec Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 6 Nov 2021 00:29:33 -0700 Subject: [PATCH 100/551] Add note concerning float sort order (#316) --- spec/API_specification/sorting_functions.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/spec/API_specification/sorting_functions.md b/spec/API_specification/sorting_functions.md index f88b01a17..fd205fbe9 100644 --- a/spec/API_specification/sorting_functions.md +++ b/spec/API_specification/sorting_functions.md @@ -8,6 +8,16 @@ A conforming implementation of the array API standard must provide and support t - Optional parameters must be [keyword-only](https://www.python.org/dev/peps/pep-3102/) arguments. - Unless stated otherwise, functions must support the data types defined in {ref}`data-types`. +```{note} +For floating-point input arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. + +Implementations may choose to sort signed zeros (`-0 < +0`) or may choose to rely solely on value equality (`==`). + +Implementations may choose to sort NaNs (e.g., to the end or to the beginning of a returned array) or leave them in-place. Should an implementation sort NaNs, the sorting convention should be clearly documented in the conforming implementation's documentation. + +While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. +``` + ## Objects in API From a5489e387aad406cdd5701e064e423ca6ed808c4 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Sat, 6 Nov 2021 03:31:08 -0400 Subject: [PATCH 101/551] Require static allocation for capsule names (#300) --- spec/design_topics/data_interchange.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/design_topics/data_interchange.md b/spec/design_topics/data_interchange.md index d01f5adad..a38602965 100644 --- a/spec/design_topics/data_interchange.md +++ b/spec/design_topics/data_interchange.md @@ -124,6 +124,9 @@ be inspected by name. The consumer must set the PyCapsule name to `"used_dltensor"`, and call the `deleter` of the `DLPackManagedTensor` when it no longer needs the data. +Note: the capsule names ``"dltensor"`` and `"used_dltensor"` must be statically +allocated. + When the `strides` field in the `DLTensor` struct is `NULL`, it indicates a row-major compact array. If the array is of size zero, the data pointer in `DLTensor` should be set to either `NULL` or `0`. From 3a6d47fe1c55988b4026370dd38b79de4a2ca807 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 7 Nov 2021 17:26:06 -0800 Subject: [PATCH 102/551] Add note concerning division by zero for integer dtypes (#311) --- spec/API_specification/array_object.md | 8 ++++++++ spec/API_specification/elementwise_functions.md | 8 ++++++++ 2 files changed, 16 insertions(+) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 303ee7a1e..6cec58210 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -628,6 +628,10 @@ Converts a zero-dimensional floating-point array to a Python `float` object. Evaluates `self_i // other_i` for each element of an array instance with the respective element of the array `other`. +```{note} +For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. +``` + #### Parameters - **self**: _<array>_ @@ -903,6 +907,10 @@ The `matmul` function must implement the same semantics as the built-in `@` oper Evaluates `self_i % other_i` for each element of an array instance with the respective element of the array `other`. +```{note} +For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. +``` + #### Parameters - **self**: _<array>_ diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 35210d7b1..58cee33af 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -668,6 +668,10 @@ Rounds each element `x_i` of the input array `x` to the greatest (i.e., closest Rounds the result of dividing each element `x1_i` of the input array `x1` by the respective element `x2_i` of the input array `x2` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. +```{note} +For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. +``` + #### Parameters - **x1**: _<array>_ @@ -1213,6 +1217,10 @@ For floating-point operands, Returns the remainder of division for each element `x1_i` of the input array `x1` and the respective element `x2_i` of the input array `x2`. +```{note} +For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. +``` + #### Parameters - **x1**: _<array>_ From 65305a4f103a19a56501eb8db92938c08f37dd25 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 7 Nov 2021 17:29:23 -0800 Subject: [PATCH 103/551] Add guidance for when rounding special floating-point values (#312) * Add guidance for when rounding special floating-point values * Update cases --- .../elementwise_functions.md | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 58cee33af..85d2c682d 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -449,6 +449,14 @@ Rounds each element `x_i` of the input array `x` to the smallest (i.e., closest - If `x_i` is already integer-valued, the result is `x_i`. +For floating-point operands, + +- If `x_i` is `+infinity`, the result is `+infinity`. +- If `x_i` is `-infinity`, the result is `-infinity`. +- If `x_i` is `+0`, the result is `+0`. +- If `x_i` is `-0`, the result is `-0`. +- If `x_i` is `NaN`, the result is `NaN`. + #### Parameters - **x**: _<array>_ @@ -651,6 +659,14 @@ Rounds each element `x_i` of the input array `x` to the greatest (i.e., closest - If `x_i` is already integer-valued, the result is `x_i`. +For floating-point operands, + +- If `x_i` is `+infinity`, the result is `+infinity`. +- If `x_i` is `-infinity`, the result is `-infinity`. +- If `x_i` is `+0`, the result is `+0`. +- If `x_i` is `-0`, the result is `-0`. +- If `x_i` is `NaN`, the result is `NaN`. + #### Parameters - **x**: _<array>_ @@ -1245,6 +1261,14 @@ Rounds each element `x_i` of the input array `x` to the nearest integer-valued n #### Special Cases - If `x_i` is already integer-valued, the result is `x_i`. + +For floating-point operands, + +- If `x_i` is `+infinity`, the result is `+infinity`. +- If `x_i` is `-infinity`, the result is `-infinity`. +- If `x_i` is `+0`, the result is `+0`. +- If `x_i` is `-0`, the result is `-0`. +- If `x_i` is `NaN`, the result is `NaN`. - If two integers are equally close to `x_i`, the result is the even integer closest to `x_i`. #### Parameters @@ -1462,6 +1486,14 @@ Rounds each element `x_i` of the input array `x` to the integer-valued number th - If `x_i` is already integer-valued, the result is `x_i`. +For floating-point operands, + +- If `x_i` is `+infinity`, the result is `+infinity`. +- If `x_i` is `-infinity`, the result is `-infinity`. +- If `x_i` is `+0`, the result is `+0`. +- If `x_i` is `-0`, the result is `-0`. +- If `x_i` is `NaN`, the result is `NaN`. + #### Parameters - **x**: _<array>_ From b6f5ad7719a43404eb45bed20beac9147e609225 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Mon, 8 Nov 2021 01:49:29 -0500 Subject: [PATCH 104/551] Add `unique_counts()` and fix the description of `unique_all()` (#317) * add unique_counts and a few fixes * fix typo * defer the discussion on index type promotion to another PR * Update note * Update type annotation Co-authored-by: Athan --- spec/API_specification/set_functions.md | 43 +++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/set_functions.md b/spec/API_specification/set_functions.md index 74408b0b1..c45f5bd54 100644 --- a/spec/API_specification/set_functions.md +++ b/spec/API_specification/set_functions.md @@ -21,7 +21,7 @@ A conforming implementation of the array API standard must provide and support t The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. ::: -Returns the unique elements of an input array `x`. +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`. ```{note} Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. @@ -55,6 +55,45 @@ Each `nan` value should have a count of one, while the counts for signed zeros s The order of unique elements is not specified and may vary between implementations. ``` +(function-unique-counts)= +### unique_counts(x, /) + +:::{admonition} Data-dependent output shape +:class: important + +The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. +::: + +Returns the unique elements of an input array `x` and the corresponding counts for each unique element in `x`. + +```{note} +Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. + +- As `nan` values compare as `False`, `nan` values should be considered distinct. +- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). + +Each `nan` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. +``` + +#### Parameters + +- **x**: _<array>_ + + - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. + +#### Returns + +- **out**: _Tuple\[ <array>, <array> ]_ + + - a namedtuple `(values, counts)` whose + + - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default integer data type. + + ```{note} + The order of unique elements is not specified and may vary between implementations. + ``` + (function-unique-inverse)= ### unique_inverse(x, /) @@ -126,4 +165,4 @@ Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). Fo ```{note} The order of unique elements is not specified and may vary between implementations. - ``` \ No newline at end of file + ``` From 1bec0e18fe6e41836ada0ed53445fc89502804c9 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Mon, 8 Nov 2021 17:12:05 +0000 Subject: [PATCH 105/551] Fix operator special cases for `__truediv__` and `__pow__` (#320) * Fix a `__truediv__` special case (machine readable) * Fix `__pow__` special case (machine readable) --- spec/API_specification/array_object.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 6cec58210..01d541670 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -1092,7 +1092,7 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - If `abs(x1_i)` is less than `1` and `x2_i` is `-infinity`, the result is `+infinity`. - If `x1_i` is `+infinity` and `x2_i` is greater than `0`, the result is `+infinity`. - If `x1_i` is `+infinity` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is `-infinity` and `x2_i` is greater than `0`, the result is `-infinity`. +- If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is an odd integer value, the result is `-infinity`. - If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is not an odd integer value, the result is `+infinity`. - If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is an odd integer value, the result is `-0`. - If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is not an odd integer value, the result is `+0`. @@ -1214,7 +1214,7 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. - If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. - If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result `-0`. +- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. - If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. - If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. - If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. From 8115f50546191f0a3c8d72eebbc6521fd3efae46 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 8 Nov 2021 13:54:06 -0800 Subject: [PATCH 106/551] Update guidance for default data types (#322) * Update guidance for default data types * Update copy --- spec/API_specification/data_types.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/data_types.md b/spec/API_specification/data_types.md index 7e295da1e..d3a49b2cd 100644 --- a/spec/API_specification/data_types.md +++ b/spec/API_specification/data_types.md @@ -110,14 +110,20 @@ Computes the truth value of `self == other` in order to test for data type objec (data-type-defaults)= ## Default Data Types -A conforming implementation of the array API standard must define a default floating-point data type (either `float32` or `float64`) and a default integer data type (`int32` or `int64`). +A conforming implementation of the array API standard must define the following default data types. -The default data types must be the same across platforms. +- a default floating-point data type (either `float32` or `float64`). +- a default integer data type (either `int32` or `int64`). +- a default array index data type (either `int32` or `int64`). -The default integer data type may vary depending on whether Python is 32-bit or 64-bit. +The default floating-point data type must be the same across platforms. + +The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. + +The default array index data type may be `int32` on 32-bit platforms, but the default should be `int64` otherwise. ```{note} -The default floating-point and integer data types should be clearly defined in a conforming library's documentation. +The default data types should be clearly defined in a conforming library's documentation. ``` (data-type-categories)= From 7525316eb26ac382dbed45c10d122703bdfa03d7 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 8 Nov 2021 13:56:48 -0800 Subject: [PATCH 107/551] Update return data types for those APIs returning indices (#323) --- spec/API_specification/set_functions.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/set_functions.md b/spec/API_specification/set_functions.md index c45f5bd54..efffef125 100644 --- a/spec/API_specification/set_functions.md +++ b/spec/API_specification/set_functions.md @@ -47,9 +47,9 @@ Each `nan` value should have a count of one, while the counts for signed zeros s - a namedtuple `(values, indices, inverse_indices, counts)` whose - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. - - second element must have the field name `indices` and must be an array containing the indices (first occurrences) of `x` that result in `values`. The array must have the same shape as `values` and must have the default integer data type. - - third element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and must have the default integer data type. - - fourth element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default integer data type. + - second element must have the field name `indices` and must be an array containing the indices (first occurrences) of `x` that result in `values`. The array must have the same shape as `values` and must have the default array index data type. + - third element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and must have the default array index data type. + - fourth element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default array index data type. ```{note} The order of unique elements is not specified and may vary between implementations. @@ -88,7 +88,7 @@ Each `nan` value should have a count of one, while the counts for signed zeros s - a namedtuple `(values, counts)` whose - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. - - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default integer data type. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default array index data type. ```{note} The order of unique elements is not specified and may vary between implementations. @@ -127,7 +127,7 @@ As signed zeros are not distinct, using `inverse_indices` to reconstruct the inp - a namedtuple `(values, inverse_indices)` whose - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. - - second element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and have the default integer data type. + - second element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and have the default array index data type. ```{note} The order of unique elements is not specified and may vary between implementations. From 11de18c1b7c394ed3f860aa0eb0ff9aa7cf24d36 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 9 Nov 2021 12:21:18 +0100 Subject: [PATCH 108/551] Update data interchange page with notes on DLPack Closes gh-192 --- spec/design_topics/data_interchange.md | 30 ++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/spec/design_topics/data_interchange.md b/spec/design_topics/data_interchange.md index a38602965..a94344db6 100644 --- a/spec/design_topics/data_interchange.md +++ b/spec/design_topics/data_interchange.md @@ -38,9 +38,11 @@ The interchange mechanism must offer the following: C/C++, and are released independently from each other. Hence a stable C ABI is required for packages to work well together._ -The best candidate for this protocol is DLPack. See the -[RFC to adopt DLPack](https://github.com/data-apis/consortium-feedback/issues/1) -for details. +The best candidate for this protocol is +[DLPack](https://github.com/dmlc/dlpack), and hence that is what this +standard has chosen as the primary/recommended protocol. Note that the +`asarray` function also supports the Python buffer protocol (CPU-only) to +support libraries that already implement buffer protocol support. ```{note} @@ -64,10 +66,26 @@ hardly has any support from array libraries. CPU interoperability is mostly dealt with via the NumPy-specific `__array__` (which, when called, means the object it is attached to must return a `numpy.ndarray` containing the data the object holds). + +See the [RFC to adopt DLPack](https://github.com/data-apis/consortium-feedback/issues/1) +for discussion that preceded the adoption of DLPack. ``` +## DLPack support + +:::{note} +DLPack is a standalone protocol/project and can therefore be used outside of +this standard. Python libraries that want to implement only DLPack support +are recommended to do so using the same syntax and semantics as outlined +below. They are not required to return an array object from `from_dlpack` +which conforms to this standard. + +DLPack itself has no documentation currently outside of the inline comments in +[dlpack.h](https://github.com/dmlc/dlpack/blob/main/include/dlpack/dlpack.h). +In the future, the below content may be migrated to the (to-be-written) DLPack docs. +::: -## Syntax for data interchange with DLPack +### Syntax for data interchange with DLPack The array API will offer the following syntax for data interchange: @@ -80,7 +98,7 @@ The array API will offer the following syntax for data interchange: stream, e.g. in the case of multiple GPUs) and to access the data. -## Semantics +### Semantics DLPack describe the memory layout of strided, n-dimensional arrays. When a user calls `y = from_dlpack(x)`, the library implementing `x` (the @@ -106,7 +124,7 @@ In the common case of the default stream being used, synchronization will be unnecessary so asynchronous execution is enabled. -## Implementation +### Implementation _Note that while this API standard largely tries to avoid discussing implementation details, some discussion and requirements are needed here because data interchange requires coordination between implementers on, e.g., memory management._ From 9efd1a32796417a473080a893fecb78700f1ad76 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 9 Nov 2021 13:00:02 -0800 Subject: [PATCH 109/551] Fix guidance for tensordot broadcasting (#324) * Fix guidance for tensordot broadcasting * Update guidance * Update note --- spec/API_specification/linear_algebra_functions.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/linear_algebra_functions.md b/spec/API_specification/linear_algebra_functions.md index 66db0d079..24d82a9e7 100644 --- a/spec/API_specification/linear_algebra_functions.md +++ b/spec/API_specification/linear_algebra_functions.md @@ -87,7 +87,11 @@ Returns a tensor contraction of `x1` and `x2` over specific axes. - **x2**: _<array>_ - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. + - second input array. Must be compatible with `x1` for all non-contracted axes (see {ref}`broadcasting`). Should have a numeric data type. + + ```{note} + Contracted axes (dimensions) must not be broadcasted. + ``` - **axes**: _Union\[ int, Tuple\[ Sequence\[ int ], Sequence\[ int ] ] ]_ From f8bbcd4d471b9fed80a097754f5ed5f1c0f59312 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 9 Nov 2021 13:02:07 -0800 Subject: [PATCH 110/551] Disallow providing a stack of vectors to `linalg.solve` (#305) * Disallow providing a stack of vectors * Update copy Co-authored-by: Leo Fang Co-authored-by: Leo Fang --- spec/extensions/linear_algebra_functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 0e432a896..bc840999a 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -484,7 +484,7 @@ Whether an array library explicitly checks whether an input array is full rank i - **x2**: _<array>_ - - ordinate (or "dependent variable") array `B`. If `x2` has shape `(..., M)`, `x2` is equivalent to an array having shape `(..., M, 1)`, and `shape(x2)` must be compatible with `shape(x1)[:-1]` (see {ref}`broadcasting`). If `x2` has shape `(..., M, K)`, each column `k` defines a set of ordinate values for which to compute a solution, and `shape(x2)[:-1]` must be compatible with `shape(x1)[:-1]` (see {ref}`broadcasting`). Should have a floating-point data type. + - ordinate (or "dependent variable") array `B`. If `x2` has shape `(M,)`, `x2` is equivalent to an array having shape `(..., M, 1)`. If `x2` has shape `(..., M, K)`, each column `k` defines a set of ordinate values for which to compute a solution, and `shape(x2)[:-1]` must be compatible with `shape(x1)[:-1]` (see {ref}`broadcasting`). Should have a floating-point data type. #### Returns From ba1ffe7ea7e18218b91dadce37a7f085bf0f01cd Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 9 Nov 2021 22:12:33 +0100 Subject: [PATCH 111/551] Update the description of the entry point in purpose and scope (#327) * Update the description of the entry point in purpose and scope Make it clearer this is optional, and why one would want to implement/use an entry point. * Update copy Co-authored-by: Matthew Barber Co-authored-by: Athan Co-authored-by: Matthew Barber --- spec/purpose_and_scope.md | 40 ++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index 4bcfb4a7e..a34208cff 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -336,11 +336,16 @@ The `xp` namespace must contain all functionality specified in including additional functionality is not recommended as doing so may hinder portability and inter-operation of array libraries within user code. -### Checking for Compliance +### Checking an array object for Compliance -Array-consuming libraries are likely to want a mechanism for determining whether a provided array is specification compliant. The recommended approach to check for compliance is by checking whether an array object has an `__array_namespace__` attribute, as this is the one distinguishing feature of an array-compliant object. +Array-consuming libraries are likely to want a mechanism for determining +whether a provided array is specification compliant. The recommended approach +to check for compliance is by checking whether an array object has an +`__array_namespace__` attribute, as this is the one distinguishing feature of +an array-compliant object. -Checking for an `__array_namespace__` attribute can be implemented as a small utility function similar to the following. +Checking for an `__array_namespace__` attribute can be implemented as a small +utility function similar to the following. ```python def is_array_api_obj(x): @@ -348,12 +353,33 @@ def is_array_api_obj(x): ``` ```{note} -Providing a "reference library" on which people depend is out-of-scope; hence, the standard cannot, e.g., provide an array ABC from which libraries can inherit to enable an `isinstance` check. +Providing a "reference library" on which people depend is out-of-scope for +the standard. Hence the standard cannot, e.g., provide an array ABC from +which libraries can inherit to enable an `isinstance` check. However, note +that the `numpy.array_api` implementation aims to provide a reference +implementation with only the behavior specified in this standard - it may +prove useful for verifying one is writing portable code. ``` -### Discoverability - -To assist array-consuming libraries which need to create arrays originating from multiple conforming array implementations, conforming implementations may provide an {pypa}`entry point ` in order to make an array API namespace discoverable. For example, +### Discoverability of conforming implementations + +It may be useful to have a way to discover all packages in a Python +environment which provide a conforming array API implementation, and the +namespace that that implementation resides in. +To assist array-consuming libraries which need to create arrays originating +from multiple conforming array implementations, or developers who want to perform +for example cross-library testing, libraries may provide an +{pypa}`entry point ` in order to make an array API +namespace discoverable. + +:::{admonition} Optional feature +Given that entry points typically require build system & package installer +specific implementation, this standard chooses to recommend rather than +mandate providing an entry point. +::: + +The following code is an example for how one can discover installed +conforming libraries: ```python from importlib.metadata import entry_points From ec731d6db95ca6ac66aeaa774200694beee388cf Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 9 Nov 2021 14:16:31 -0800 Subject: [PATCH 112/551] Remove `axis` kwarg support from `matrix_norm` (#321) --- spec/extensions/linear_algebra_functions.md | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index bc840999a..2e054f8aa 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -261,7 +261,7 @@ Returns the multiplicative inverse of a square matrix (or a stack of square matr Alias for {ref}`function-matmul`. (function-linalg-matrix-norm)= -### linalg.matrix_norm(x, /, *, axis=(-2, -1), keepdims=False, ord='fro') +### linalg.matrix_norm(x, /, *, keepdims=False, ord='fro') Computes the matrix norm of a matrix (or a stack of matrices) `x`. @@ -269,15 +269,11 @@ Computes the matrix norm of a matrix (or a stack of matrices) `x`. - **x**: _<array>_ - - input array. Must have at least `2` dimensions. Should have a floating-point data type. - -- **axis**: _Tuple\[ int, int ]_ - - - a 2-tuple which specifies the axes (dimensions) defining two-dimensional matrices for which to compute matrix norms. Negative indices must be supported. Default: `(-2, -1)` (i.e., the last two-dimensions). + - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - **keepdims**: _bool_ - - If `True`, the axes (dimensions) specified by `axis` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the axes (dimensions) specified by `axis` must not be included in the result. Default: `False`. + - If `True`, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the last two axes (dimensions) must not be included in the result. Default: `False`. - **ord**: _Optional\[ Union\[ int, float, Literal\[ inf, -inf, 'fro', 'nuc' ] ] ]_ @@ -309,7 +305,7 @@ Computes the matrix norm of a matrix (or a stack of matrices) `x`. - **out**: _<array>_ - - an array containing the norms. If `keepdims` is `False`, the returned array must have a rank which is two less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. + - an array containing the norms for each `MxN` matrix. If `keepdims` is `False`, the returned array must have a rank which is two less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. (function-linalg-matrix_power)= ### linalg.matrix_power(x, n, /) From 4c041ea353745bfb4e4ebe5e1f54b6709d4e13e7 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 11 Nov 2021 01:35:02 +0000 Subject: [PATCH 113/551] `expand_dims()` signature change (and slight doc fix) (#331) * Fix incorrect output shape behaviour in `expand_dims()` * Keep `expand_dims()` signature in-line with `squeeze()` --- spec/API_specification/manipulation_functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/manipulation_functions.md b/spec/API_specification/manipulation_functions.md index 1f140bcb0..36f59b4c7 100644 --- a/spec/API_specification/manipulation_functions.md +++ b/spec/API_specification/manipulation_functions.md @@ -39,7 +39,7 @@ Joins a sequence of arrays along an existing axis. ``` (function-expand_dims)= -### expand_dims(x, /, *, axis) +### expand_dims(x, /, axis) Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by `axis`. @@ -57,7 +57,7 @@ Expands the shape of an array by inserting a new axis (dimension) of size one at - **out**: _<array>_ - - an expanded output array having the same data type and shape as `x`. + - an expanded output array having the same data type as `x`. (function-flip)= ### flip(x, /, *, axis=None) From 02fae2cb00449c0e8bfbb27aa5cf707e5658f34a Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 15 Nov 2021 14:23:58 -0800 Subject: [PATCH 114/551] Fix `matmul` broadcasting guidance (#328) * Add commas * Clarify broadcasting rules --- spec/API_specification/array_object.md | 18 +++++++++--------- .../linear_algebra_functions.md | 18 +++++++++--------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 01d541670..5d801b72c 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -870,23 +870,23 @@ The `matmul` function must implement the same semantics as the built-in `@` oper - **self**: _<array>_ - - array instance. Should have a numeric data type. Must have at least one dimension. If `self` is one-dimensional having shape `(M)` and `other` has more than one dimension, `self` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `self` has more than one dimension (including after vector-to-matrix promotion), `self` must be compatible with `other` (see {ref}`broadcasting`). If `self` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. + - array instance. Should have a numeric data type. Must have at least one dimension. If `self` is one-dimensional having shape `(M,)` and `other` has more than one dimension, `self` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `self` has more than one dimension (including after vector-to-matrix promotion), `shape(self)[:-2]` must be compatible with `shape(other)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `self` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - **other**: _<array>_ - - other array. Should have a numeric data type. Must have at least one dimension. If `other` is one-dimensional having shape `(N)` and `self` has more than one dimension, `other` must be promoted to a two-dimensional array by appending `1` to its dimensions (i.e., must have shape `(N, 1)`). After matrix multiplication, the appended dimensions in the returned array must be removed. If `other` has more than one dimension (including after vector-to-matrix promotion), `other` must be compatible with `self` (see {ref}`broadcasting`). If `other` has shape `(..., K, N)`, the innermost two dimensions form matrices on which to perform matrix multiplication. + - other array. Should have a numeric data type. Must have at least one dimension. If `other` is one-dimensional having shape `(N,)` and `self` has more than one dimension, `other` must be promoted to a two-dimensional array by appending `1` to its dimensions (i.e., must have shape `(N, 1)`). After matrix multiplication, the appended dimensions in the returned array must be removed. If `other` has more than one dimension (including after vector-to-matrix promotion), `shape(other)[:-2]` must be compatible with `shape(self)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `other` has shape `(..., K, N)`, the innermost two dimensions form matrices on which to perform matrix multiplication. #### Returns - **out**: _<array>_ - - if both `self` and `other` are one-dimensional arrays having shape `(N)`, a zero-dimensional array containing the inner product as its only element. + - if both `self` and `other` are one-dimensional arrays having shape `(N,)`, a zero-dimensional array containing the inner product as its only element. - if `self` is a two-dimensional array having shape `(M, K)` and `other` is a two-dimensional array having shape `(K, N)`, a two-dimensional array containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) and having shape `(M, N)`. - - if `self` is a one-dimensional array having shape `(K)` and `other` is an array having shape `(..., K, N)`, an array having shape `(..., N)` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `self` is an array having shape `(..., M, K)` and `other` is a one-dimensional array having shape `(K)`, an array having shape `(..., M)` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). + - if `self` is a one-dimensional array having shape `(K,)` and `other` is an array having shape `(..., K, N)`, an array having shape `(..., N)` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). + - if `self` is an array having shape `(..., M, K)` and `other` is a one-dimensional array having shape `(K,)`, an array having shape `(..., M)` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - if `self` is a two-dimensional array having shape `(M, K)` and `other` is an array having shape `(..., K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - if `self` is an array having shape `(..., M, K)` and `other` is a two-dimensional array having shape `(K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if either `self` or `other` has more than two dimensions, an array having a shape determined by {ref}`broadcasting` `self` against `other` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. + - if either `self` or `other` has more than two dimensions, an array having a shape determined by {ref}`broadcasting` `shape(self)[:-2]` against `shape(other)[:-2]` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. The returned array must have a data type determined by {ref}`type-promotion`. @@ -897,9 +897,9 @@ The `matmul` function must implement the same semantics as the built-in `@` oper #### Raises - if either `self` or `other` is a zero-dimensional array. -- if `self` is a one-dimensional array having shape `(K)`, `other` is a one-dimensional array having shape `(L)`, and `K != L`. -- if `self` is a one-dimensional array having shape `(K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. -- if `self` is an array having shape `(..., M, K)`, `other` is a one-dimensional array having shape `(L)`, and `K != L`. +- if `self` is a one-dimensional array having shape `(K,)`, `other` is a one-dimensional array having shape `(L,)`, and `K != L`. +- if `self` is a one-dimensional array having shape `(K,)`, `other` is an array having shape `(..., L, N)`, and `K != L`. +- if `self` is an array having shape `(..., M, K)`, `other` is a one-dimensional array having shape `(L,)`, and `K != L`. - if `self` is an array having shape `(..., M, K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. (method-__mod__)= diff --git a/spec/API_specification/linear_algebra_functions.md b/spec/API_specification/linear_algebra_functions.md index 24d82a9e7..ce911de6e 100644 --- a/spec/API_specification/linear_algebra_functions.md +++ b/spec/API_specification/linear_algebra_functions.md @@ -29,32 +29,32 @@ The `matmul` function must implement the same semantics as the built-in `@` oper - **x1**: _<array>_ - - first input array. Should have a numeric data type. Must have at least one dimension. If `x1` is one-dimensional having shape `(M)` and `x2` has more than one dimension, `x1` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `x1` has more than one dimension (including after vector-to-matrix promotion), `x1` must be compatible with `x2` (see {ref}`broadcasting`). If `x1` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. + - first input array. Should have a numeric data type. Must have at least one dimension. If `x1` is one-dimensional having shape `(M,)` and `x2` has more than one dimension, `x1` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `x1` has more than one dimension (including after vector-to-matrix promotion), `shape(x1)[:-2]` must be compatible with `shape(x2)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `x1` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - **x2**: _<array>_ - - second input array. Should have a numeric data type. Must have at least one dimension. If `x2` is one-dimensional having shape `(N)` and `x1` has more than one dimension, `x2` must be promoted to a two-dimensional array by appending `1` to its dimensions (i.e., must have shape `(N, 1)`). After matrix multiplication, the appended dimensions in the returned array must be removed. If `x2` has more than one dimension (including after vector-to-matrix promotion), `x2` must be compatible with `x1` (see {ref}`broadcasting`). If `x2` has shape `(..., K, N)`, the innermost two dimensions form matrices on which to perform matrix multiplication. + - second input array. Should have a numeric data type. Must have at least one dimension. If `x2` is one-dimensional having shape `(N,)` and `x1` has more than one dimension, `x2` must be promoted to a two-dimensional array by appending `1` to its dimensions (i.e., must have shape `(N, 1)`). After matrix multiplication, the appended dimensions in the returned array must be removed. If `x2` has more than one dimension (including after vector-to-matrix promotion), `shape(x2)[:-2]` must be compatible with `shape(x1)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `x2` has shape `(..., K, N)`, the innermost two dimensions form matrices on which to perform matrix multiplication. #### Returns - **out**: _<array>_ - - if both `x1` and `x2` are one-dimensional arrays having shape `(N)`, a zero-dimensional array containing the inner product as its only element. + - if both `x1` and `x2` are one-dimensional arrays having shape `(N,)`, a zero-dimensional array containing the inner product as its only element. - if `x1` is a two-dimensional array having shape `(M, K)` and `x2` is a two-dimensional array having shape `(K, N)`, a two-dimensional array containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) and having shape `(M, N)`. - - if `x1` is a one-dimensional array having shape `(K)` and `x2` is an array having shape `(..., K, N)`, an array having shape `(..., N)` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `x1` is an array having shape `(..., M, K)` and `x2` is a one-dimensional array having shape `(K)`, an array having shape `(..., M)` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). + - if `x1` is a one-dimensional array having shape `(K,)` and `x2` is an array having shape `(..., K, N)`, an array having shape `(..., N)` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). + - if `x1` is an array having shape `(..., M, K)` and `x2` is a one-dimensional array having shape `(K,)`, an array having shape `(..., M)` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - if `x1` is a two-dimensional array having shape `(M, K)` and `x2` is an array having shape `(..., K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - if `x1` is an array having shape `(..., M, K)` and `x2` is a two-dimensional array having shape `(K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if either `x1` or `x2` has more than two dimensions, an array having a shape determined by {ref}`broadcasting` `x1` against `x2` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. + - if either `x1` or `x2` has more than two dimensions, an array having a shape determined by {ref}`broadcasting` `shape(x1)[:-2]` against `shape(x2)[:-2]` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. The returned array must have a data type determined by {ref}`type-promotion`. #### Raises - if either `x1` or `x2` is a zero-dimensional array. -- if `x1` is a one-dimensional array having shape `(K)`, `x2` is a one-dimensional array having shape `(L)`, and `K != L`. -- if `x1` is a one-dimensional array having shape `(K)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. -- if `x1` is an array having shape `(..., M, K)`, `x2` is a one-dimensional array having shape `(L)`, and `K != L`. +- if `x1` is a one-dimensional array having shape `(K,)`, `x2` is a one-dimensional array having shape `(L,)`, and `K != L`. +- if `x1` is a one-dimensional array having shape `(K,)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. +- if `x1` is an array having shape `(..., M, K)`, `x2` is a one-dimensional array having shape `(L,)`, and `K != L`. - if `x1` is an array having shape `(..., M, K)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. (function-matrix-transpose)= From f4fb0f284ebf6851c60955742062ddb23210a726 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 18 Nov 2021 09:36:52 -0800 Subject: [PATCH 115/551] Update guidance for `pow` and `divide` concerning arrays with integer dtypes (#330) --- spec/API_specification/array_object.md | 8 +++++++- spec/API_specification/elementwise_functions.md | 14 ++++++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 5d801b72c..73e51f8c4 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -1075,6 +1075,12 @@ Element-wise results must equal the results returned by the equivalent element-w Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of `other_i` (the exponent), where `other_i` is the corresponding element of the array `other`. +```{note} +If both `self` and `other` have integer data types, the result of `__pow__` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + +If `self` has an integer data type and `other` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). +``` + #### Special Cases For floating-point operands, let `self` equal `x1` and `other` equal `x2`. @@ -1247,7 +1253,7 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - **out**: _<array>_ - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. + - an array containing the element-wise results. The returned array should have a floating-point data type determined by {ref}`type-promotion`. ```{note} Element-wise results must equal the results returned by the equivalent element-wise function [`divide(x1, x2)`](elementwise_functions.md#dividex1-x2-). diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 85d2c682d..5bd0477f0 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -559,11 +559,11 @@ For floating-point operands, - **x1**: _<array>_ - - dividend input array. Should have a floating-point data type. + - dividend input array. Should have a numeric data type. - **x2**: _<array>_ - - divisor input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a floating-point data type. + - divisor input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. #### Returns @@ -1183,6 +1183,12 @@ Computes the numerical positive of each element `x_i` (i.e., `y_i = +x_i`) of th Calculates an implementation-dependent approximation of exponentiation by raising each element `x1_i` (the base) of the input array `x1` to the power of `x2_i` (the exponent), where `x2_i` is the corresponding element of the input array `x2`. +```{note} +If both `x1` and `x2` have integer data types, the result of `pow` when `x2_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + +If `x1` has an integer data type and `x2` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). +``` + #### Special Cases For floating-point operands, @@ -1216,11 +1222,11 @@ For floating-point operands, - **x1**: _<array>_ - - first input array whose elements correspond to the exponentiation base. Should have a floating-point data type. + - first input array whose elements correspond to the exponentiation base. Should have a numeric data type. - **x2**: _<array>_ - - second input array whose elements correspond to the exponentiation exponent. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a floating-point data type. + - second input array whose elements correspond to the exponentiation exponent. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. #### Returns From e181da89db4a010bbbef21ee1241c02b1e8d7f57 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Mon, 22 Nov 2021 13:58:27 -0600 Subject: [PATCH 116/551] Changes Implementation section of data-interchange to close #337 (#338) * Changes Implementation section of data-interchange to close #337 * Clarify expectations of consumer/producer with respect to lifetime management of DLManagedTensor passed via Python capsule --- spec/design_topics/data_interchange.md | 41 +++++++++++++++++++------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/spec/design_topics/data_interchange.md b/spec/design_topics/data_interchange.md index a94344db6..5084c42f1 100644 --- a/spec/design_topics/data_interchange.md +++ b/spec/design_topics/data_interchange.md @@ -126,24 +126,38 @@ unnecessary so asynchronous execution is enabled. ### Implementation -_Note that while this API standard largely tries to avoid discussing implementation details, some discussion and requirements are needed here because data interchange requires coordination between implementers on, e.g., memory management._ +_Note that while this API standard largely tries to avoid discussing +implementation details, some discussion and requirements are needed +here because data interchange requires coordination between +implementers on, e.g., memory management._ ![Diagram of DLPack structs](/_static/images/DLPack_diagram.png) -_DLPack diagram. Dark blue are the structs it defines, light blue struct members, gray text enum values of supported devices and data types._ +_DLPack diagram. Dark blue are the structs it defines, light blue +struct members, gray text enum values of supported devices and data +types._ The `__dlpack__` method will produce a `PyCapsule` containing a -`DLPackManagedTensor`, which will be consumed immediately within +`DLManagedTensor`, which will be consumed immediately within `from_dlpack` - therefore it is consumed exactly once, and it will not be visible to users of the Python API. -The producer must set the PyCapsule name to ``"dltensor"`` so that it can -be inspected by name. -The consumer must set the PyCapsule name to `"used_dltensor"`, and call the -`deleter` of the `DLPackManagedTensor` when it no longer needs the data. +The producer must set the `PyCapsule` name to ``"dltensor"`` so that +it can be inspected by name, and set `PyCapsule_Destructor` that calls +the `deleter` of the `DLManagedTensor` when the `"dltensor"`-named +capsule is no longer needed. -Note: the capsule names ``"dltensor"`` and `"used_dltensor"` must be statically -allocated. +The consumer must transer ownership of the `DLManangedTensor` from the +capsule to its own object. It does so by renaming the capsule to +`"used_dltensor"` to ensure that `PyCapsule_Destructor` will not get +called (ensured if `PyCapsule_Destructor` calls `deleter` only for +capsules whose name is `"dltensor"`), but the `deleter` of the +`DLManagedTensor` will be called by the destructor of the consumer +library object created to own the `DLManagerTensor` obtained from the +capsule. + +Note: the capsule names ``"dltensor"`` and `"used_dltensor"` must be +statically allocated. When the `strides` field in the `DLTensor` struct is `NULL`, it indicates a row-major compact array. If the array is of size zero, the data pointer in @@ -153,8 +167,13 @@ DLPack version used must be `0.2 <= DLPACK_VERSION < 1.0`. For further details on DLPack design and how to implement support for it, refer to [github.com/dmlc/dlpack](https://github.com/dmlc/dlpack). -:::{warning} -DLPack contains a `device_id`, which will be the device ID (an integer, `0, 1, ...`) which the producer library uses. In practice this will likely be the same numbering as that of the consumer, however that is not guaranteed. Depending on the hardware type, it may be possible for the consumer library implementation to look up the actual device from the pointer to the data - this is possible for example for CUDA device pointers. +:::{warning} DLPack contains a `device_id`, which will be the device +ID (an integer, `0, 1, ...`) which the producer library uses. In +practice this will likely be the same numbering as that of the +consumer, however that is not guaranteed. Depending on the hardware +type, it may be possible for the consumer library implementation to +look up the actual device from the pointer to the data - this is +possible for example for CUDA device pointers. It is recommended that implementers of this array API consider and document whether the `.device` attribute of the array returned from `from_dlpack` is From 3e4764817700966878bebe0a8733e1f7c415a0c8 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Nov 2021 01:56:09 -0800 Subject: [PATCH 117/551] Add floating-point special cases for `floor_divide` (#329) * Add special cases for `floor_divide` * Add note and demarcate special cases with expected deviations * Update copy --- spec/API_specification/array_object.md | 39 ++++++++++++++++++- .../elementwise_functions.md | 39 ++++++++++++++++++- 2 files changed, 76 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 73e51f8c4..e950643b4 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -632,6 +632,43 @@ Evaluates `self_i // other_i` for each element of an array instance with the res For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. ``` +#### Special Cases + +```{note} +Floor division was introduced in Python via [PEP 238](https://www.python.org/dev/peps/pep-0238/) with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a `float`, while the latter was computed when both operands were `int`s. Overloading the `/` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + +To resolve this ambiguity, `/` was designated for true division, and `//` was designated for floor division. Semantically, floor division was [defined](https://www.python.org/dev/peps/pep-0238/#semantics-of-floor-division) as equivalent to `a // b == floor(a/b)`; however, special floating-point cases were left ill-defined. + +Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is `infinity`, libraries may diverge with some choosing to strictly follow `floor(a/b)` and others choosing to pair `//` with `%` according to the relation `b = a % b + b * (a // b)`. The special cases leading to divergent behavior are documented below. + +This specification prefers floor division to match `floor(divide(x1, x2))` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. +``` + +For floating-point operands, let `self` equal `x1` and `other` equal `x2`. + +- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. +- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. +- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. +- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. +- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. +- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. +- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. +- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. +- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. +- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. +- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. +- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. +- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) +- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) +- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. +- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. +- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. +- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + #### Parameters - **self**: _<array>_ @@ -1237,7 +1274,7 @@ For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. - If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too larger to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. +- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. #### Parameters diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index 5bd0477f0..f7adb7373 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -553,7 +553,7 @@ For floating-point operands, - If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. - If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too larger to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. +- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. #### Parameters @@ -688,6 +688,43 @@ Rounds the result of dividing each element `x1_i` of the input array `x1` by the For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. ``` +#### Special Cases + +```{note} +Floor division was introduced in Python via [PEP 238](https://www.python.org/dev/peps/pep-0238/) with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a `float`, while the latter was computed when both operands were `int`s. Overloading the `/` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + +To resolve this ambiguity, `/` was designated for true division, and `//` was designated for floor division. Semantically, floor division was [defined](https://www.python.org/dev/peps/pep-0238/#semantics-of-floor-division) as equivalent to `a // b == floor(a/b)`; however, special floating-point cases were left ill-defined. + +Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is `infinity`, libraries may diverge with some choosing to strictly follow `floor(a/b)` and others choosing to pair `//` with `%` according to the relation `b = a % b + b * (a // b)`. The special cases leading to divergent behavior are documented below. + +This specification prefers floor division to match `floor(divide(x1, x2))` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. +``` + +For floating-point operands, + +- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. +- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. +- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. +- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. +- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. +- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. +- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. +- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. +- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. +- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. +- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. +- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) +- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. +- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) +- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) +- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. +- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. +- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. +- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + #### Parameters - **x1**: _<array>_ From 11a3d2cf4fb350fed00ab8b48620266076b3be93 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 29 Nov 2021 02:31:36 -0800 Subject: [PATCH 118/551] Update guidance for unsigned integer data types (#340) --- spec/API_specification/statistical_functions.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md index debccc185..d126f3e57 100644 --- a/spec/API_specification/statistical_functions.md +++ b/spec/API_specification/statistical_functions.md @@ -134,7 +134,9 @@ For an input array `x`, let `N` equal the number of elements over which to compu - data type of the returned array. If `None`, - if the default data type corresponding to the data type "kind" (integer or floating-point) of `x` has a smaller range of values than the data type of `x` (e.g., `x` has data type `int64` and the default data type is `int32`, or `x` has data type `uint64` and the default data type is `int64`), the returned array must have the same data type as `x`. - - otherwise, the returned array must have the default data type corresponding to the data type "kind" (integer or floating-point) of `x`. + - if `x` has a floating-point data type, the returned array must have the default floating-point data type. + - if `x` has a signed integer data type (e.g., `int16`), the returned array must have the default integer data type. + - if `x` has an unsigned integer data type (e.g., `uint16`), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is `int32`, the returned array must have a `uint32` data type). If the data type (either specified or resolved) differs from the data type of `x`, the input array should be cast to the specified data type before computing the product. Default: `None`. @@ -217,7 +219,9 @@ For an input array `x`, let `N` equal the number of elements over which to compu - data type of the returned array. If `None`, - if the default data type corresponding to the data type "kind" (integer or floating-point) of `x` has a smaller range of values than the data type of `x` (e.g., `x` has data type `int64` and the default data type is `int32`, or `x` has data type `uint64` and the default data type is `int64`), the returned array must have the same data type as `x`. - - otherwise, the returned array must have the default data type corresponding to the data type "kind" (integer or floating-point) of `x`. + - if `x` has a floating-point data type, the returned array must have the default floating-point data type. + - if `x` has a signed integer data type (e.g., `int16`), the returned array must have the default integer data type. + - if `x` has an unsigned integer data type (e.g., `uint16`), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is `int32`, the returned array must have a `uint32` data type). If the data type (either specified or resolved) differs from the data type of `x`, the input array should be cast to the specified data type before computing the sum. Default: `None`. From 545d7f1819225e6d45333330ef58c79356fb110d Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Mon, 6 Dec 2021 18:27:01 +0000 Subject: [PATCH 119/551] Special case when NaNs present in statistical functions (#335) * Special case NaNs in all statistical functions * Update notes This commit brings the formatting and language in-line with element-wise and array object methods. * Capitalize similar to element-wise and array object docs Co-authored-by: Athan --- .../statistical_functions.md | 43 ++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md index d126f3e57..fb0ca7c21 100644 --- a/spec/API_specification/statistical_functions.md +++ b/spec/API_specification/statistical_functions.md @@ -24,6 +24,12 @@ Calculates the maximum value of the input array `x`. When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the minimum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `-infinity`). ``` +#### Special Cases + +For floating-point operands, + +- If `x_i` is `NaN`, the maximum value is `NaN` (i.e., `NaN` values propagate). + #### Parameters - **x**: _<array>_ @@ -51,9 +57,10 @@ Calculates the arithmetic mean of the input array `x`. #### Special Cases -For a floating-point input array `x`, let `N` equal the number of elements over which to compute the arithmetic mean and +Let `N` equal the number of elements over which to compute the arithmetic mean. -- if `N` is `0`, the arithmetic mean is `NaN`. +- If `N` is `0`, the arithmetic mean is `NaN`. +- If `x_i` is `NaN`, the arithmetic mean is `NaN` (i.e., `NaN` values propagate). #### Parameters @@ -88,6 +95,12 @@ Calculates the minimum value of the input array `x`. When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the maximum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `+infinity`). ``` +#### Special Cases + +For floating-point operands, + +- If `x_i` is `NaN`, the minimum value is `NaN` (i.e., `NaN` values propagate). + #### Parameters - **x**: _<array>_ @@ -115,9 +128,13 @@ Calculates the product of input array `x` elements. #### Special Cases -For an input array `x`, let `N` equal the number of elements over which to compute the product and +Let `N` equal the number of elements over which to compute the product. + +- If `N` is `0`, the product is `1` (i.e., the empty product). -- if `N` is `0`, the product is `1` (i.e., the empty product). +For floating-point operands, + +- If `x_i` is `NaN`, the product is `NaN` (i.e., `NaN` values propagate). #### Parameters @@ -161,9 +178,10 @@ Calculates the standard deviation of the input array `x`. #### Special Cases -For a floating-point input array `x`, let `N` equal the number of elements over which to compute the standard deviation and +Let `N` equal the number of elements over which to compute the standard deviation. -- if `N - correction` is less than or equal to `0`, the standard deviation is `NaN`. +- If `N - correction` is less than or equal to `0`, the standard deviation is `NaN`. +- If `x_i` is `NaN`, the standard deviation is `NaN` (i.e., `NaN` values propagate). #### Parameters @@ -200,9 +218,13 @@ Calculates the sum of the input array `x`. #### Special Cases -For an input array `x`, let `N` equal the number of elements over which to compute the sum and +Let `N` equal the number of elements over which to compute the sum. + +- If `N` is `0`, the sum is `0` (i.e., the empty sum). + +For floating-point operands, -- if `N` is `0`, the sum is `0` (i.e., the empty sum). +- If `x_i` is `NaN`, the sum is `NaN` (i.e., `NaN` values propagate). #### Parameters @@ -246,9 +268,10 @@ Calculates the variance of the input array `x`. #### Special Cases -For a floating-point input array `x`, let `N` equal the number of elements over which to compute the variance and +Let `N` equal the number of elements over which to compute the variance. -- if `N - correction` is less than or equal to `0`, the variance is `NaN`. +- If `N - correction` is less than or equal to `0`, the variance is `NaN`. +- If `x_i` is `NaN`, the variance is `NaN` (i.e., `NaN` values propagate). #### Parameters From 657a8f4c195cc0f72cecfa7086c8d7ad56a69cbc Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 6 Dec 2021 14:42:33 -0500 Subject: [PATCH 120/551] Transform sorting function specification file from Markdown to RST (#333) * Transform sorting functions from md to rst file * Fix the warning message * Add autosummary with signatures for the sorting functions * Bump CI python to 3.8 * Complete signatures and add types files * Remove module names and add autodoc typehints * Bump Sphinx version * Remove module import from signature and return annonation * Add jinja template for autosummary * Put return section style as parameters and remove return type section --- .circleci/config.yml | 2 +- .gitignore | 2 + requirements.txt | 2 +- spec/API_specification/signatures/__init__.py | 0 spec/API_specification/signatures/_types.py | 40 +++++++++ .../signatures/sorting_functions.py | 45 +++++++++++ spec/API_specification/sorting_functions.md | 81 ------------------- spec/API_specification/sorting_functions.rst | 34 ++++++++ spec/_templates/method.rst | 5 ++ spec/conf.py | 26 +++++- 10 files changed, 150 insertions(+), 87 deletions(-) create mode 100644 spec/API_specification/signatures/__init__.py create mode 100644 spec/API_specification/signatures/_types.py create mode 100644 spec/API_specification/signatures/sorting_functions.py delete mode 100644 spec/API_specification/sorting_functions.md create mode 100644 spec/API_specification/sorting_functions.rst create mode 100644 spec/_templates/method.rst diff --git a/.circleci/config.yml b/.circleci/config.yml index cb1031906..829dcbb64 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ _defaults: &defaults docker: # CircleCI maintains a library of pre-built images # documented at https://circleci.com/docs/2.0/circleci-images/ - - image: circleci/python:3.7.0 + - image: circleci/python:3.8.0 working_directory: ~/repo jobs: diff --git a/.gitignore b/.gitignore index a740a2929..dfedda47f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ spec/_build/ build/ .vscode/ node_modules/ +__pycache__/ +*.pyc \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 5df0b2504..4741c6dc8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -sphinx==3.1.1 +sphinx==4.3.0 sphinx-material==0.0.30 myst-parser sphinx_markdown_tables diff --git a/spec/API_specification/signatures/__init__.py b/spec/API_specification/signatures/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/spec/API_specification/signatures/_types.py b/spec/API_specification/signatures/_types.py new file mode 100644 index 000000000..6c0b5b85a --- /dev/null +++ b/spec/API_specification/signatures/_types.py @@ -0,0 +1,40 @@ +""" +This file defines the types for type annotations. + +The type variables should be replaced with the actual types for a given +library, e.g., for NumPy TypeVar('array') would be replaced with ndarray. +""" + +from dataclasses import dataclass +from typing import Any, List, Literal, Optional, Sequence, Tuple, TypeVar, Union + +array = TypeVar('array') +device = TypeVar('device') +dtype = TypeVar('dtype') +SupportsDLPack = TypeVar('SupportsDLPack') +SupportsBufferProtocol = TypeVar('SupportsBufferProtocol') +PyCapsule = TypeVar('PyCapsule') +# ellipsis cannot actually be imported from anywhere, so include a dummy here +# to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 +ellipsis = TypeVar('ellipsis') + +@dataclass +class finfo_object: + bits: int + eps: float + max: float + min: float + smallest_normal: float + +@dataclass +class iinfo_object: + bits: int + max: int + min: int + +# This should really be recursive, but that isn't supported yet. +NestedSequence = Sequence[Sequence[Any]] + +__all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', +'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', +'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object'] \ No newline at end of file diff --git a/spec/API_specification/signatures/sorting_functions.py b/spec/API_specification/signatures/sorting_functions.py new file mode 100644 index 000000000..715a3e817 --- /dev/null +++ b/spec/API_specification/signatures/sorting_functions.py @@ -0,0 +1,45 @@ +from ._types import array + +def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + """ + Returns the indices that sort an array ``x`` along a specified axis. + + Parameters + ---------- + x : array + input array. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the returned indices sort ``x`` in descending order (by value). If ``False``, the returned indices sort ``x`` in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned indices must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned indices may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. + """ + +def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + """ + Returns a sorted copy of an input array ``x``. + + Parameters + ---------- + x: array + input array. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the array must be sorted in descending order (by value). If ``False``, the array must be sorted in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned array must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned array may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + a sorted array. The returned array must have the same data type and shape as ``x``. + """ + +__all__ = ['argsort', 'sort'] \ No newline at end of file diff --git a/spec/API_specification/sorting_functions.md b/spec/API_specification/sorting_functions.md deleted file mode 100644 index fd205fbe9..000000000 --- a/spec/API_specification/sorting_functions.md +++ /dev/null @@ -1,81 +0,0 @@ -# Sorting Functions - -> Array API specification for sorting functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) arguments. -- Unless stated otherwise, functions must support the data types defined in {ref}`data-types`. - -```{note} -For floating-point input arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. - -Implementations may choose to sort signed zeros (`-0 < +0`) or may choose to rely solely on value equality (`==`). - -Implementations may choose to sort NaNs (e.g., to the end or to the beginning of a returned array) or leave them in-place. Should an implementation sort NaNs, the sorting convention should be clearly documented in the conforming implementation's documentation. - -While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. -``` - -## Objects in API - - - -(function-argsort)= -### argsort(x, /, *, axis=-1, descending=False, stable=True) - -Returns the indices that sort an array `x` along a specified axis. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axis**: _int_ - - - axis along which to sort. If set to `-1`, the function must sort along the last axis. Default: `-1`. - -- **descending**: _bool_ - - - sort order. If `True`, the returned indices sort `x` in descending order (by value). If `False`, the returned indices sort `x` in ascending order (by value). Default: `False`. - -- **stable**: _bool_ - - - sort stability. If `True`, the returned indices must maintain the relative order of `x` values which compare as equal. If `False`, the returned indices may or may not maintain the relative order of `x` values which compare as equal (i.e., the relative order of `x` values which compare as equal is implementation-dependent). Default: `True`. - -#### Returns - -- **out**: _<array>_ - - - an array of indices. The returned array must have the same shape as `x`. The returned array must have the default array index data type. - -(function-sort)= -### sort(x, /, *, axis=-1, descending=False, stable=True) - -Returns a sorted copy of an input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axis**: _int_ - - - axis along which to sort. If set to `-1`, the function must sort along the last axis. Default: `-1`. - -- **descending**: _bool_ - - - sort order. If `True`, the array must be sorted in descending order (by value). If `False`, the array must be sorted in ascending order (by value). Default: `False`. - -- **stable**: _bool_ - - - sort stability. If `True`, the returned array must maintain the relative order of `x` values which compare as equal. If `False`, the returned array may or may not maintain the relative order of `x` values which compare as equal (i.e., the relative order of `x` values which compare as equal is implementation-dependent). Default: `True`. - -#### Returns - -- **out**: _<array>_ - - - a sorted array. The returned array must have the same data type and shape as `x`. diff --git a/spec/API_specification/sorting_functions.rst b/spec/API_specification/sorting_functions.rst new file mode 100644 index 000000000..da0ff99d1 --- /dev/null +++ b/spec/API_specification/sorting_functions.rst @@ -0,0 +1,34 @@ +Sorting Functions +================= + + Array API specification for sorting functions. + +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. +* Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. + +.. note:: + + For floating-point input arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. + + Implementations may choose to sort signed zeros (``-0 < +0``) or may choose to rely solely on value equality (``==``). + + Implementations may choose to sort NaNs (e.g., to the end or to the beginning of a returned array) or leave them in-place. Should an implementation sort NaNs, the sorting convention should be clearly documented in the conforming implementation's documentation. + + While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. + +.. currentmodule:: signatures.sorting_functions + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argsort + sort diff --git a/spec/_templates/method.rst b/spec/_templates/method.rst new file mode 100644 index 000000000..3a85f2879 --- /dev/null +++ b/spec/_templates/method.rst @@ -0,0 +1,5 @@ +.. currentmodule:: {{ module }} + +{{ name.split('.')[-1] | underline }} + +.. autofunction:: {{ name }} diff --git a/spec/conf.py b/spec/conf.py index ffb1e94a2..5370da268 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -10,11 +10,10 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -# import os -# import sys -# sys.path.insert(0, os.path.abspath('.')) - +import os +import sys import sphinx_material +sys.path.insert(0, os.path.abspath('./API_specification')) # -- Project information ----------------------------------------------------- @@ -38,8 +37,16 @@ 'sphinx.ext.todo', 'sphinx_markdown_tables', 'sphinx_copybutton', + 'sphinx.ext.autosummary', + 'sphinx.ext.napoleon', + 'sphinx.ext.autodoc', ] +autosummary_generate = True +autodoc_typehints = 'signature' +add_module_names = False +napoleon_custom_sections = [('Returns', 'params_style')] + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -145,3 +152,14 @@ "dudir": ("http://docutils.sourceforge.net/docs/ref/rst/" "directives.html#%s", ""), "pypa": ("https://packaging.python.org/%s", ""), } + + +def process_signature(app, what, name, obj, options, signature, return_annotation): + if signature: + signature = signature.replace("signatures._types.", "") + if return_annotation: + return_annotation = return_annotation.replace("signatures._types.", "") + return signature, return_annotation + +def setup(app): + app.connect("autodoc-process-signature", process_signature) \ No newline at end of file From 0602a5ff4e55e9e33e2a537e81867c0b14e5b148 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Dec 2021 11:46:06 -0800 Subject: [PATCH 121/551] Add note concerning subnormal numbers (#341) --- spec/API_specification/data_types.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/data_types.md b/spec/API_specification/data_types.md index d3a49b2cd..de4798b41 100644 --- a/spec/API_specification/data_types.md +++ b/spec/API_specification/data_types.md @@ -50,14 +50,19 @@ IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-20 IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). +```{note} +IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + +Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. +``` :::{admonition} Future extension :class: hint -`complex64` and `complex128` dtypes are expected to be included in the next +`complex64` and `complex128` data types are expected to be included in the next version of this standard and to have the following casting rules (will be added to {ref}`type-promotion`): -![Type promotion diagram for complex dtypes in next version](/_static/images/dtype_promotion_complex.png) +![Type promotion diagram for complex data types in next version](/_static/images/dtype_promotion_complex.png) See [array-api/issues/102](https://github.com/data-apis/array-api/issues/102) for more details. @@ -132,7 +137,7 @@ The default data types should be clearly defined in a conforming library's docum For the purpose of organizing functions within this specification, the following data type categories are defined. ```{note} -Conforming libraries are not required to organize dtypes according to these categories. These +Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. ``` @@ -144,7 +149,7 @@ complex data types. ### Numeric Data Types `int8`, `int16`, `int32`, `int64`, `uint8`, `uint16`, `uint32`, -`uint64`, `float32`, and `float64` (i.e., all dtypes except for `bool`). +`uint64`, `float32`, and `float64` (i.e., all data types except for `bool`). ### Integer Data Types From a854ff17ba71f079461cc16decca875adf55dc85 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 8 Dec 2021 23:05:01 +0000 Subject: [PATCH 122/551] Specify numeric arrays for `argmin` and `argmax` (#342) --- spec/API_specification/searching_functions.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/searching_functions.md b/spec/API_specification/searching_functions.md index f0311b8b7..7bf3f346e 100644 --- a/spec/API_specification/searching_functions.md +++ b/spec/API_specification/searching_functions.md @@ -25,7 +25,7 @@ Returns the indices of the maximum values along a specified axis. When the maxim - **x**: _<array>_ - - input array. + - input array. Should have a numeric data type. - **axis**: _Optional\[ int ]_ @@ -50,7 +50,7 @@ Returns the indices of the minimum values along a specified axis. When the minim - **x**: _<array>_ - - input array. + - input array. Should have a numeric data type. - **axis**: _Optional\[ int ]_ From 9c11e7222d7f338e4e5ade49734ee25229dbff9c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 14 Dec 2021 12:19:56 -0500 Subject: [PATCH 123/551] Convert array_object.md to rst --- spec/API_specification/array_object.md | 1351 ----------------- spec/API_specification/array_object.rst | 311 ++++ spec/API_specification/signatures/_types.py | 3 +- .../signatures/array_object.py | 942 ++++++++++++ 4 files changed, 1255 insertions(+), 1352 deletions(-) delete mode 100644 spec/API_specification/array_object.md create mode 100644 spec/API_specification/array_object.rst create mode 100644 spec/API_specification/signatures/array_object.py diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md deleted file mode 100644 index e950643b4..000000000 --- a/spec/API_specification/array_object.md +++ /dev/null @@ -1,1351 +0,0 @@ -(array-object)= - -# Array object - -> Array API specification for array object attributes and methods. - -A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods adhering to the following conventions. - -- Positional parameters must be [positional-only](https://www.python.org/dev/peps/pep-0570/) parameters. Positional-only parameters have no externally-usable name. When a method accepting positional-only parameters is called, positional arguments are mapped to these parameters based solely on their order. -- Optional parameters must be [keyword-only](https://www.python.org/dev/peps/pep-3102/) arguments. -- Broadcasting semantics must follow the semantics defined in {ref}`broadcasting`. -- Unless stated otherwise, methods must support the data types defined in {ref}`data-types`. -- Unless stated otherwise, methods must adhere to the type promotion rules defined in {ref}`type-promotion`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -Furthermore, a conforming implementation of the array API standard must support array objects of arbitrary rank `N` (i.e., number of dimensions), where `N` is greater than or equal to zero. - -```{note} -Conforming implementations must support zero-dimensional arrays. - -Apart from array object attributes, such as `ndim`, `device`, and `dtype`, all operations in this standard return arrays (or tuples of arrays), including those operations, such as `mean`, `var`, and `std`, from which some common array libraries (e.g., NumPy) return scalar values. - -_Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value._ -``` - -* * * - -(operators)= - -## Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. - -### Arithmetic Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. - -- `+x`: [`__pos__(x)`](#__pos__self-) - - - [`operator.pos(x)`](https://docs.python.org/3/library/operator.html#operator.pos) - - [`operator.__pos__(x)`](https://docs.python.org/3/library/operator.html#operator.__pos__) - -- `-x`: [`__neg__(x)`](#__neg__self-) - - - [`operator.neg(x)`](https://docs.python.org/3/library/operator.html#operator.neg) - - [`operator.__neg__(x)`](https://docs.python.org/3/library/operator.html#operator.__neg__) - -- `x1 + x2`: [`__add__(x1, x2)`](#__add__self-other-) - - - [`operator.add(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.add) - - [`operator.__add__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__add__) - -- `x1 - x2`: [`__sub__(x1, x2)`](#__sub__self-other-) - - - [`operator.sub(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.sub) - - [`operator.__sub__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__sub__) - -- `x1 * x2`: [`__mul__(x1, x2)`](#__mul__self-other-) - - - [`operator.mul(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.mul) - - [`operator.__mul__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__mul__) - -- `x1 / x2`: [`__truediv__(x1, x2)`](#__truediv__self-other-) - - - [`operator.truediv(x1,x2)`](https://docs.python.org/3/library/operator.html#operator.truediv) - - [`operator.__truediv__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__truediv__) - -- `x1 // x2`: [`__floordiv__(x1, x2)`](#__floordiv__self-other-) - - - [`operator.floordiv(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.floordiv) - - [`operator.__floordiv__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__floordiv__) - -- `x1 % x2`: [`__mod__(x1, x2)`](#__mod__self-other-) - - - [`operator.mod(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.mod) - - [`operator.__mod__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__mod__) - -- `x1 ** x2`: [`__pow__(x1, x2)`](#__pow__self-other-) - - - [`operator.pow(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.pow) - - [`operator.__pow__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__pow__) - -Arithmetic operators should be defined for arrays having numeric data types. - -### Array Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. - -- `x1 @ x2`: [`__matmul__(x1, x2)`](#__matmul__self-other-) - - - [`operator.matmul(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.matmul) - - [`operator.__matmul__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__matmul__) - -The matmul `@` operator should be defined for arrays having numeric data types. - -### Bitwise Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. - -- `~x`: [`__invert__(x)`](#__invert__self-) - - - [`operator.inv(x)`](https://docs.python.org/3/library/operator.html#operator.inv) - - [`operator.invert(x)`](https://docs.python.org/3/library/operator.html#operator.invert) - - [`operator.__inv__(x)`](https://docs.python.org/3/library/operator.html#operator.__inv__) - - [`operator.__invert__(x)`](https://docs.python.org/3/library/operator.html#operator.__invert__) - -- `x1 & x2`: [`__and__(x1, x2)`](#__and__self-other-) - - - [`operator.and(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.and) - - [`operator.__and__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__and__) - -- `x1 | x2`: [`__or__(x1, x2)`](#__or__self-other-) - - - [`operator.or(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.or) - - [`operator.__or__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__or__) - -- `x1 ^ x2`: [`__xor__(x1, x2)`](#__xor__self-other-) - - - [`operator.xor(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.xor) - - [`operator.__xor__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__xor__) - -- `x1 << x2`: [`__lshift__(x1, x2)`](#__lshift__self-other-) - - - [`operator.lshift(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.lshift) - - [`operator.__lshift__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__lshift__) - -- `x1 >> x2`: [`__rshift__(x1, x2)`](#__rshift__self-other-) - - - [`operator.rshift(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.rshift) - - [`operator.__rshift__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__rshift__) - -Bitwise operators should be defined for arrays having integer and boolean data types. - -### Comparison Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. - -- `x1 < x2`: [`__lt__(x1, x2)`](#__lt__self-other-) - - - [`operator.lt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.lt) - - [`operator.__lt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__lt__) - -- `x1 <= x2`: [`__le__(x1, x2)`](#__le__self-other-) - - - [`operator.le(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.le) - - [`operator.__le__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__le__) - -- `x1 > x2`: [`__gt__(x1, x2)`](#__gt__self-other-) - - - [`operator.gt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.gt) - - [`operator.__gt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__gt__) - -- `x1 >= x2`: [`__ge__(x1, x2)`](#__ge__self-other-) - - - [`operator.ge(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ge) - - [`operator.__ge__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ge__) - -- `x1 == x2`: [`__eq__(x1, x2)`](#__eq__self-other-) - - - [`operator.eq(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.eq) - - [`operator.__eq__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__eq__) - -- `x1 != x2`: [`__ne__(x1, x2)`](#__ne__self-other-) - - - [`operator.ne(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ne) - - [`operator.__ne__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ne__) - -Comparison operators should be defined for arrays having any data type. - -### In-place Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. - -An in-place operation must not change the data type or shape of the in-place array as a result of {ref}`type-promotion` or {ref}`broadcasting`. - -An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition `x1 += x2`, the modified array `x1` must always equal the result of the equivalent binary arithmetic operation `x1 = x1 + x2`. - -```{note} -In-place operators must be supported as discussed in {ref}`copyview-mutability`. -``` - -#### Arithmetic Operators - -- `+=`. May be implemented via `__iadd__`. -- `-=`. May be implemented via `__isub__`. -- `*=`. May be implemented via `__imul__`. -- `/=`. May be implemented via `__itruediv__`. -- `//=`. May be implemented via `__ifloordiv__`. -- `**=`. May be implemented via `__ipow__`. -- `%=`. May be implemented via `__imod__`. - -#### Array Operators - -- `@=`. May be implemented via `__imatmul__`. - -#### Bitwise Operators - -- `&=`. May be implemented via `__iand__`. -- `|=`. May be implemented via `__ior__`. -- `^=`. May be implemented via `__ixor__`. -- `<<=`. May be implemented via `__ilshift__`. -- `>>=`. May be implemented via `__irshift__`. - -### Reflected Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. - -The results of applying reflected operators must match their non-reflected equivalents. - -```{note} -All operators for which `array scalar` is implemented must have an equivalent reflected operator implementation. -``` - -#### Arithmetic Operators - -- `__radd__` -- `__rsub__` -- `__rmul__` -- `__rtruediv__` -- `__rfloordiv__` -- `__rpow__` -- `__rmod__` - -#### Array Operators - -- `__rmatmul__` - -#### Bitwise Operators - -- `__rand__` -- `__ror__` -- `__rxor__` -- `__rlshift__` -- `__rrshift__` - -* * * - -## Attributes - - - -(attribute-dtype)= -### dtype - -Data type of the array elements. - -#### Returns - -- **out**: _<dtype>_ - - - array data type. - -(attribute-device)= -### device - -Hardware device the array data resides on. - -#### Returns - -- **out**: _<device>_ - - - a `device` object (see {ref}`device-support`). - -(attribute-mT)= -### mT - -Transpose of a matrix (or a stack of matrices). - -If an array instance has fewer than two dimensions, an error should be raised. - -#### Returns - -- **out**: _<array>_ - - - array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape `(..., M, N)`, the returned array must have shape `(..., N, M)`). The returned array must have the same data type as the original array. - -(attribute-ndim)= -### ndim - -Number of array dimensions (axes). - -#### Returns - -- **out**: _int_ - - - number of array dimensions (axes). - -(attribute-shape)= -### shape - -Array dimensions. - -#### Returns - -- **out**: _Tuple\[ Optional\[ int ], ... ]_ - - - array dimensions. An array dimension must be `None` if and only if a dimension is unknown. - -```{note} -For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; `A[:, B > 0]`) and thus cannot be statically resolved without knowing array contents. -``` - -```{note} -The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. -``` - -(attribute-size)= -### size - -Number of elements in an array. - -```{note} -This must equal the product of the array's dimensions. -``` - -#### Returns - -- **out**: _Optional\[ int ]_ - - - number of elements in an array. The returned value must be `None` if and only if one or more array dimensions are unknown. - -```{note} -For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. -``` - -(attribute-T)= -### T - -Transpose of the array. - -The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. - -```{note} -Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional `permute_dims` interface found in this specification. -``` - -#### Returns - -- **out**: _<array>_ - - - two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. - -* * * - -## Methods - - - -(method-__abs__)= -### \_\_abs\_\_(self, /) - -Calculates the absolute value for each element of an array instance (i.e., the element-wise result has the same magnitude as the respective element but has positive sign). - -```{note} -For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. -``` - -#### Special Cases - -For floating-point operands, let `self` equal `x`. - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `-0`, the result is `+0`. -- If `x_i` is `-infinity`, the result is `+infinity`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise absolute value. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`abs(x)`](elementwise_functions.md#absx-). -``` - -(method-__add__)= -### \_\_add\_\_(self, other, /) - -Calculates the sum for each element of an array instance with the respective element of the array `other`. - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is `+infinity` and `x2_i` is `-infinity`, the result is `NaN`. -- If `x1_i` is `-infinity` and `x2_i` is `+infinity`, the result is `NaN`. -- If `x1_i` is `+infinity` and `x2_i` is `+infinity`, the result is `+infinity`. -- If `x1_i` is `-infinity` and `x2_i` is `-infinity`, the result is `-infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a finite number, the result is `+infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a finite number, the result is `-infinity`. -- If `x1_i` is a finite number and `x2_i` is `+infinity`, the result is `+infinity`. -- If `x1_i` is a finite number and `x2_i` is `-infinity`, the result is `-infinity`. -- If `x1_i` is `-0` and `x2_i` is `-0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is `+0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `-0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `+0`, the result is `+0`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is a nonzero finite number, the result is `x2_i`. -- If `x1_i` is a nonzero finite number and `x2_i` is either `+0` or `-0`, the result is `x1_i`. -- If `x1_i` is a nonzero finite number and `x2_i` is `-x1_i`, the result is `+0`. -- In the remaining cases, when neither `infinity`, `+0`, `-0`, nor a `NaN` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. - -```{note} -Floating-point addition is a commutative operation, but not always associative. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance (augend array). Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - addend array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise sums. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`add(x1, x2)`](elementwise_functions.md#addx1-x2-). -``` - -(method-__and__)= -### \_\_and\_\_(self, other, /) - -Evaluates `self_i & other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -- **other**: _Union\[ int, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_and(x1, x2)`](elementwise_functions.md#logical_andx1-x2-). -``` - - -(method-__array_namespace__)= -### \_\_array_namespace\_\_(self, /, *, api_version=None) - -Returns an object that has all the array API functions on it. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **api_version**: _<Optional\[str\]>_ - - - string representing the version of the array API specification to be returned, in `'YYYY.MM'` form, for example, `'2020.10'`. If it is `None`, it should return the namespace corresponding to latest version of the array API specification. If the given version is invalid or not implemented for the given module, an error should be raised. Default: `None`. - -#### Returns - -- **out**: _<object>_ - - - an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. - - -(method-__bool__)= -### \_\_bool\_\_(self, /) - -Converts a zero-dimensional boolean array to a Python `bool` object. - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have a boolean data type. - -#### Returns - -- **out**: _<bool>_ - - - a Python `bool` object representing the single element of the array. - - -(method-__dlpack__)= -### \_\_dlpack\_\_(self, /, *, stream=None) - -Exports the array for consumption by {ref}`function-from_dlpack` as a DLPack capsule. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **stream**: _Optional\[ Union\[ int, Any ]]_ - - - for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. `stream` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be a positive integer or `-1`. If `stream` is `-1`, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. - - On CPU and other device types without streams, only `None` is accepted. - - For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for `stream` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order `cl::sycl::queue`. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. - - ```{note} - Support for a `stream` value other than `None` is optional and implementation-dependent. - ``` - - Device-specific notes: - - :::{admonition} CUDA - - `None`: producer must assume the legacy default stream (default). - - `1`: the legacy default stream. - - `2`: the per-thread default stream. - - `> 2`: stream number represented as a Python integer. - - `0` is disallowed due to its ambiguity: `0` could mean either `None`, `1`, or `2`. - ::: - - :::{admonition} ROCm - - `None`: producer must assume the legacy default stream (default). - - `0`: the default stream. - - `> 2`: stream number represented as a Python integer. - - Using `1` and `2` is not supported. - ::: - - ```{tip} - It is recommended that implementers explicitly handle streams. If - they use the legacy default stream, specifying `1` (CUDA) or `0` - (ROCm) is preferred. `None` is a safe default for developers who do - not want to think about stream handling at all, potentially at the - cost of more synchronization than necessary. - ``` - -#### Returns - -- **capsule**: _<PyCapsule>_ - - - a DLPack capsule for the array. See {ref}`data-interchange` for details. - - -(method-__dlpack_device__)= -### \_\_dlpack\_device\_\_(self, /) - -Returns device type and device ID in DLPack format. Meant for use within {ref}`function-from_dlpack`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -#### Returns - -- **device**: _Tuple\[enum.IntEnum, int\]_ - - - a tuple `(device_type, device_id)` in DLPack format. Valid device type enum members are: - - ``` - CPU = 1 - CUDA = 2 - CPU_PINNED = 3 - OPENCL = 4 - VULKAN = 7 - METAL = 8 - VPI = 9 - ROCM = 10 - ``` - -(method-__eq__)= -### \_\_eq\_\_(self, other, /) - -Computes the truth value of `self_i == other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. May have any data type. - -- **other**: _Union\[ int, float, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). May have any data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`equal(x1, x2)`](elementwise_functions.md#equalx1-x2-). -``` - -(method-__float__)= -### \_\_float\_\_(self, /) - -Converts a zero-dimensional floating-point array to a Python `float` object. - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have a floating-point data type. - -#### Returns - -- **out**: _<float>_ - - - a Python `float` object representing the single element of the array instance. - -(method-__floordiv__)= -### \_\_floordiv\_\_(self, other, /) - -Evaluates `self_i // other_i` for each element of an array instance with the respective element of the array `other`. - -```{note} -For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. -``` - -#### Special Cases - -```{note} -Floor division was introduced in Python via [PEP 238](https://www.python.org/dev/peps/pep-0238/) with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a `float`, while the latter was computed when both operands were `int`s. Overloading the `/` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. - -To resolve this ambiguity, `/` was designated for true division, and `//` was designated for floor division. Semantically, floor division was [defined](https://www.python.org/dev/peps/pep-0238/#semantics-of-floor-division) as equivalent to `a // b == floor(a/b)`; however, special floating-point cases were left ill-defined. - -Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is `infinity`, libraries may diverge with some choosing to strictly follow `floor(a/b)` and others choosing to pair `//` with `%` according to the relation `b = a % b + b * (a // b)`. The special cases leading to divergent behavior are documented below. - -This specification prefers floor division to match `floor(divide(x1, x2))` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. -``` - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. -- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. -- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. -- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`floor_divide(x1, x2)`](elementwise_functions.md#floor_dividex1-x2-). -``` - -(method-__ge__)= -### \_\_ge\_\_(self, other, /) - -Computes the truth value of `self_i >= other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`greater_equal(x1, x2)`](elementwise_functions.md#greater_equalx1-x2-). -``` - -(method-__getitem__)= -### \_\_getitem\_\_(self, key, /) - -Returns `self[key]`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **key**: _Union\[ int, slice, ellipsis, Tuple\[ Union\[ int, slice, ellipsis ], ... ], <array> ]_ - - - index key. - -#### Returns - -- **out**: _<array>_ - - - an array containing the accessed value(s). The returned array must have the same data type as `self`. - -(method-__gt__)= -### \_\_gt\_\_(self, other, /) - -Computes the truth value of `self_i > other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`greater(x1, x2)`](elementwise_functions.md#greaterx1-x2-). -``` - -(method-__index__)= -### \_\_index\_\_(self, /) - -Converts a zero-dimensional integer array to a Python `int` object. - -```{note} -This method is called to implement [`operator.index()`](https://docs.python.org/3/reference/datamodel.html#object.__index__). See also [PEP 357](https://www.python.org/dev/peps/pep-0357/). -``` - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have an integer data type. - -#### Returns - -- **out**: _<int>_ - - - a Python `int` object representing the single element of the array instance. - -(method-__int__)= -### \_\_int\_\_(self, /) - -Converts a zero-dimensional integer array to a Python `int` object. - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have an integer data type. - -#### Returns - -- **out**: _<int>_ - - - a Python `int` object representing the single element of the array instance. - -(method-__invert__)= -### \_\_invert\_\_(self, /) - -Evaluates `~self_i` for each element of an array instance. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_invert(x)`](elementwise_functions.md#bitwise_invertx-). -``` - -(method-__le__)= -### \_\_le\_\_(self, other, /) - -Computes the truth value of `self_i <= other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`less_equal(x1, x2)`](elementwise_functions.md#less_equalx1-x2-). -``` - -(method-__lshift__)= -### \_\_lshift\_\_(self, other, /) - -Evaluates `self_i << other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer data type. - -- **other**: _Union\[ int, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer data type. Each element must be greater than or equal to `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_left_shift(x1, x2)`](elementwise_functions.md#bitwise_left_shiftx1-x2-). -``` - -(method-__lt__)= -### \_\_lt\_\_(self, other, /) - -Computes the truth value of `self_i < other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`less(x1, x2)`](elementwise_functions.md#lessx1-x2-). -``` - -(method-__matmul__)= -### \_\_matmul\_\_(self, other, /) - -Computes the matrix product. - -```{note} -The `matmul` function must implement the same semantics as the built-in `@` operator (see [PEP 465](https://www.python.org/dev/peps/pep-0465)). -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. Must have at least one dimension. If `self` is one-dimensional having shape `(M,)` and `other` has more than one dimension, `self` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `self` has more than one dimension (including after vector-to-matrix promotion), `shape(self)[:-2]` must be compatible with `shape(other)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `self` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - -- **other**: _<array>_ - - - other array. Should have a numeric data type. Must have at least one dimension. If `other` is one-dimensional having shape `(N,)` and `self` has more than one dimension, `other` must be promoted to a two-dimensional array by appending `1` to its dimensions (i.e., must have shape `(N, 1)`). After matrix multiplication, the appended dimensions in the returned array must be removed. If `other` has more than one dimension (including after vector-to-matrix promotion), `shape(other)[:-2]` must be compatible with `shape(self)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `other` has shape `(..., K, N)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - -#### Returns - -- **out**: _<array>_ - - - if both `self` and `other` are one-dimensional arrays having shape `(N,)`, a zero-dimensional array containing the inner product as its only element. - - if `self` is a two-dimensional array having shape `(M, K)` and `other` is a two-dimensional array having shape `(K, N)`, a two-dimensional array containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) and having shape `(M, N)`. - - if `self` is a one-dimensional array having shape `(K,)` and `other` is an array having shape `(..., K, N)`, an array having shape `(..., N)` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `self` is an array having shape `(..., M, K)` and `other` is a one-dimensional array having shape `(K,)`, an array having shape `(..., M)` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `self` is a two-dimensional array having shape `(M, K)` and `other` is an array having shape `(..., K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if `self` is an array having shape `(..., M, K)` and `other` is a two-dimensional array having shape `(K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if either `self` or `other` has more than two dimensions, an array having a shape determined by {ref}`broadcasting` `shape(self)[:-2]` against `shape(other)[:-2]` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - The returned array must have a data type determined by {ref}`type-promotion`. - - ```{note} - Results must equal the results returned by the equivalent function [`matmul(x1, x2)`](linear_algebra_functions.md#matmulx1-x2-). - ``` - -#### Raises - -- if either `self` or `other` is a zero-dimensional array. -- if `self` is a one-dimensional array having shape `(K,)`, `other` is a one-dimensional array having shape `(L,)`, and `K != L`. -- if `self` is a one-dimensional array having shape `(K,)`, `other` is an array having shape `(..., L, N)`, and `K != L`. -- if `self` is an array having shape `(..., M, K)`, `other` is a one-dimensional array having shape `(L,)`, and `K != L`. -- if `self` is an array having shape `(..., M, K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. - -(method-__mod__)= -### \_\_mod\_\_(self, other, /) - -Evaluates `self_i % other_i` for each element of an array instance with the respective element of the array `other`. - -```{note} -For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element `other_i`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`remainder(x1, x2)`](elementwise_functions.md#remainderx1-x2-). -``` - -(method-__mul__)= -### \_\_mul\_\_(self, other, /) - -Calculates the product for each element of an array instance with the respective element of the array `other`. - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` and `x2_i` have the same mathematical sign, the result has a positive mathematical sign, unless the result is `NaN`. If the result is `NaN`, the "sign" of `NaN` is implementation-defined. -- If `x1_i` and `x2_i` have different mathematical signs, the result has a negative mathematical sign, unless the result is `NaN`. If the result is `NaN`, the "sign" of `NaN` is implementation-defined. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- If `x1_i` is a nonzero finite number and `x2_i` is either `+infinity` or `-infinity`, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- In the remaining cases, where neither `infinity` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. - -```{note} -Floating-point multiplication is not always associative due to finite precision. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise products. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`multiply(x1, x2)`](elementwise_functions.md#multiplyx1-x2-). -``` - -(method-__ne__)= -### \_\_ne\_\_(self, other, /) - -Computes the truth value of `self_i != other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. May have any data type. - -- **other**: _Union\[ int, float, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). May have any data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool` (i.e., must be a boolean array). - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`not_equal(x1, x2)`](elementwise_functions.md#not_equalx1-x2-). -``` - -(method-__neg__)= -### \_\_neg\_\_(self, /) - -Evaluates `-self_i` for each element of an array instance. - -```{note} -For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `self`. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`negative(x)`](elementwise_functions.md#negativex-). -``` - -(method-__or__)= -### \_\_or\_\_(self, other, /) - -Evaluates `self_i | other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -- **other**: _Union\[ int, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_or(x1, x2)`](elementwise_functions.md#bitwise_orx1-x2-). -``` - -(method-__pos__)= -### \_\_pos\_\_(self, /) - -Evaluates `+self_i` for each element of an array instance. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`positive(x)`](elementwise_functions.md#positivex-). -``` - -(method-__pow__)= -### \_\_pow\_\_(self, other, /) - -Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of `other_i` (the exponent), where `other_i` is the corresponding element of the array `other`. - -```{note} -If both `self` and `other` have integer data types, the result of `__pow__` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - -If `self` has an integer data type and `other` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). -``` - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If `x1_i` is not equal to `1` and `x2_i` is `NaN`, the result is `NaN`. -- If `x2_i` is `+0`, the result is `1`, even if `x1_i` is `NaN`. -- If `x2_i` is `-0`, the result is `1`, even if `x1_i` is `NaN`. -- If `x1_i` is `NaN` and `x2_i` is not equal to `0`, the result is `NaN`. -- If `abs(x1_i)` is greater than `1` and `x2_i` is `+infinity`, the result is `+infinity`. -- If `abs(x1_i)` is greater than `1` and `x2_i` is `-infinity`, the result is `+0`. -- If `abs(x1_i)` is `1` and `x2_i` is `+infinity`, the result is `1`. -- If `abs(x1_i)` is `1` and `x2_i` is `-infinity`, the result is `1`. -- If `x1_i` is `1` and `x2_i` is not `NaN`, the result is `1`. -- If `abs(x1_i)` is less than `1` and `x2_i` is `+infinity`, the result is `+0`. -- If `abs(x1_i)` is less than `1` and `x2_i` is `-infinity`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is greater than `0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is an odd integer value, the result is `-infinity`. -- If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is not an odd integer value, the result is `+infinity`. -- If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is an odd integer value, the result is `-0`. -- If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is not an odd integer value, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `+infinity`. -- If `x1_i` is `-0`, `x2_i` is greater than `0`, and `x2_i` is an odd integer value, the result is `-0`. -- If `x1_i` is `-0`, `x2_i` is greater than `0`, and `x2_i` is not an odd integer value, the result is `+0`. -- If `x1_i` is `-0`, `x2_i` is less than `0`, and `x2_i` is an odd integer value, the result is `-infinity`. -- If `x1_i` is `-0`, `x2_i` is less than `0`, and `x2_i` is not an odd integer value, the result is `+infinity`. -- If `x1_i` is less than `0`, `x1_i` is a finite number, `x2_i` is a finite number, and `x2_i` is not an integer value, the result is `NaN`. - -#### Parameters - -- **self**: _<array>_ - - - array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array whose elements correspond to the exponentiation exponent. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`pow(x1, x2)`](elementwise_functions.md#powx1-x2-). -``` - -(method-__rshift__)= -### \_\_rshift\_\_(self, other, /) - -Evaluates `self_i >> other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer data type. - -- **other**: _Union\[ int, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer data type. Each element must be greater than or equal to `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_right_shift(x1, x2)`](elementwise_functions.md#bitwise_right_shiftx1-x2-). -``` - -(method-__setitem__)= -### \_\_setitem\_\_(self, key, value, /) - -Sets `self[key]` to `value`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **key**: _Union\[ int, slice, ellipsis, Tuple\[ Union\[ int, slice, ellipsis ], ... ], <array> ]_ - - - index key. - -- **value**: _Union\[ int, float, bool, <array> ]_ - - - value(s) to set. Must be compatible with `self[key]` (see {ref}`broadcasting`). - -```{note} -Setting array values must not affect the data type of `self`. - -When `value` is a Python scalar (i.e., `int`, `float`, `bool`), behavior must follow specification guidance on mixing arrays with Python scalars (see {ref}`type-promotion`). - -When `value` is an `array` of a different data type than `self`, how values are cast to the data type of `self` is implementation defined. -``` - -(method-__sub__)= -### \_\_sub\_\_(self, other, /) - -Calculates the difference for each element of an array instance with the respective element of the array `other`. The result of `self_i - other_i` must be the same as `self_i + (-other_i)` and must be governed by the same floating-point rules as addition (see [`__add__()`](#__add__self-other-)). - -#### Parameters - -- **self**: _<array>_ - - - array instance (minuend array). Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - subtrahend array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise differences. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`subtract(x1, x2)`](elementwise_functions.md#subtractx1-x2-). -``` - -(method-__truediv__)= -### \_\_truediv\_\_(self, other, /) - -Evaluates `self_i / other_i` for each element of an array instance with the respective element of the array `other`. - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. -- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. -- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. -- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array should have a floating-point data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`divide(x1, x2)`](elementwise_functions.md#dividex1-x2-). -``` - -(method-__xor__)= -### \_\_xor\_\_(self, other, /) - -Evaluates `self_i ^ other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -- **other**: _Union\[ int, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_xor(x1, x2)`](elementwise_functions.md#bitwise_xorx1-x2-). -``` - -(method-to_device)= -### to\_device(self, device, /, *, stream=None) - -Copy the array from the device on which it currently resides to the specified `device`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **device**: _<device>_ - - - a `device` object (see {ref}`device-support`). - -- **stream**: _Optional\[ Union\[ int, Any ]]_ - - - stream object to use during copy. In addition to the types supported in {ref}`method-__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. - -#### Returns - -- **out**: _<array>_ - - - an array with the same data and data type as `self` and located on the specified `device`. - -```{note} -If `stream` is given, the copy operation should be enqueued on the provided `stream`; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. -``` diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst new file mode 100644 index 000000000..33a6e9e86 --- /dev/null +++ b/spec/API_specification/array_object.rst @@ -0,0 +1,311 @@ +.. _array-object: + +Array object +============ + + Array API specification for array object attributes and methods. + +A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods adhering to the following conventions. + +* Positional parameters must be `positional-only `_ parameters. Positional-only parameters have no externally-usable name. When a method 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, methods must support the data types defined in :ref:`data-types`. +* Unless stated otherwise, methods must adhere to the type promotion rules defined in :ref:`type-promotion`. +* Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. + +Furthermore, a conforming implementation of the array API standard must support array objects of arbitrary rank ``N`` (i.e., number of dimensions), where ``N`` is greater than or equal to zero. + +.. note:: + Conforming implementations must support zero-dimensional arrays. + + Apart from array object attributes, such as ``ndim``, ``device``, and ``dtype``, all operations in this standard return arrays (or tuples of arrays), including those operations, such as ``mean``, ``var``, and ``std``, from which some common array libraries (e.g., NumPy) return scalar values. + + *Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value.* + +------------------------------------------------- + +.. _operators: + +Operators +--------- + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. + +Arithmetic Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. + +- ``+x``: :meth:`array.__pos__` + + - `operator.pos(x) `_ + - `operator.__pos__(x) `_ + +- `-x`: :meth:`array.__neg__` + + - `operator.neg(x) `_ + - `operator.__neg__(x) `_ + +- `x1 + x2`: :meth:`array.__add__` + + - `operator.add(x1, x2) `_ + - `operator.__add__(x1, x2) `_ + +- `x1 - x2`: :meth:`array.__sub__` + + - `operator.sub(x1, x2) `_ + - `operator.__sub__(x1, x2) `_ + +- `x1 * x2`: :meth:`array.__mul__` + + - `operator.mul(x1, x2) `_ + - `operator.__mul__(x1, x2) `_ + +- `x1 / x2`: :meth:`array.__truediv__` + + - `operator.truediv(x1,x2) `_ + - `operator.__truediv__(x1, x2) `_ + +- `x1 // x2`: :meth:`array.__floordiv__` + + - `operator.floordiv(x1, x2) `_ + - `operator.__floordiv__(x1, x2) `_ + +- `x1 % x2`: :meth:`array.__mod__` + + - `operator.mod(x1, x2) `_ + - `operator.__mod__(x1, x2) `_ + +- `x1 ** x2`: :meth:`array.__pow__` + + - `operator.pow(x1, x2) `_ + - `operator.__pow__(x1, x2) `_ + +Arithmetic operators should be defined for arrays having numeric data types. + +Array Operators +~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. + +- `x1 @ x2`: :meth:`array.__matmul__` + + - `operator.matmul(x1, x2) `_ + - `operator.__matmul__(x1, x2) `_ + +The matmul ``@`` operator should be defined for arrays having numeric data types. + +Bitwise Operators +~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. + +- `~x`: :meth:`array.__invert__` + + - `operator.inv(x) `_ + - `operator.invert(x) `_ + - `operator.__inv__(x) `_ + - `operator.__invert__(x) `_ + +- `x1 & x2`: :meth:`array.__and__` + + - `operator.and(x1, x2) `_ + - `operator.__and__(x1, x2) `_ + +- `x1 | x2`: :meth:`array.__or__` + + - `operator.or(x1, x2) `_ + - `operator.__or__(x1, x2) `_ + +- `x1 ^ x2`: :meth:`array.__xor__` + + - `operator.xor(x1, x2) `_ + - `operator.__xor__(x1, x2) `_ + +- `x1 << x2`: :meth:`array.__lshift__` + + - `operator.lshift(x1, x2) `_ + - `operator.__lshift__(x1, x2) `_ + +- `x1 >> x2`: :meth:`array.__rshift__` + + - `operator.rshift(x1, x2) `_ + - `operator.__rshift__(x1, x2) `_ + +Bitwise operators should be defined for arrays having integer and boolean data types. + +Comparison Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. + +- `x1 < x2`: :meth:`array.__lt__` + + - `operator.lt(x1, x2) `_ + - `operator.__lt__(x1, x2) `_ + +- `x1 <= x2`: :meth:`array.__le__` + + - `operator.le(x1, x2) `_ + - `operator.__le__(x1, x2) `_ + +- `x1 > x2`: :meth:`array.__gt__` + + - `operator.gt(x1, x2) `_ + - `operator.__gt__(x1, x2) `_ + +- `x1 >= x2`: :meth:`array.__ge__` + + - `operator.ge(x1, x2) `_ + - `operator.__ge__(x1, x2) `_ + +- `x1 == x2`: :meth:`array.__eq__` + + - `operator.eq(x1, x2) `_ + - `operator.__eq__(x1, x2) `_ + +- `x1 != x2`: :meth:`array.__ne__` + + - `operator.ne(x1, x2) `_ + - `operator.__ne__(x1, x2) `_ + +Comparison operators should be defined for arrays having any data type. + +In-place Operators +~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. + +An in-place operation must not change the data type or shape of the in-place array as a result of :ref:`type-promotion` or :ref:`broadcasting`. + +An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1 = x1 + x2``. + +.. note:: +In-place operators must be supported as discussed in :ref:`copyview-mutability`. + +Arithmetic Operators +"""""""""""""""""""" + +- ``+=``. May be implemented via ``__iadd__``. +- ``-=``. May be implemented via ``__isub__``. +- ``*=``. May be implemented via ``__imul__``. +- ``/=``. May be implemented via ``__itruediv__``. +- ``//=``. May be implemented via ``__ifloordiv__``. +- ``**=``. May be implemented via ``__ipow__``. +- ``%=``. May be implemented via ``__imod__``. + +Array Operators +""""""""""""""" + +- ``@=``. May be implemented via ``__imatmul__``. + +Bitwise Operators +""""""""""""""""" + +- ``&=``. May be implemented via ``__iand__``. +- ``|=``. May be implemented via ``__ior__``. +- ``^=``. May be implemented via ``__ixor__``. +- ``<<=``. May be implemented via ``__ilshift__``. +- ``>>=``. May be implemented via ``__irshift__``. + +Reflected Operators +~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. + +The results of applying reflected operators must match their non-reflected equivalents. + +.. note:: +All operators for which ``array scalar`` is implemented must have an equivalent reflected operator implementation. + +Arithmetic Operators +"""""""""""""""""""" + +- ``__radd__`` +- ``__rsub__`` +- ``__rmul__`` +- ``__rtruediv__`` +- ``__rfloordiv__`` +- ``__rpow__`` +- ``__rmod__`` + +Array Operators +""""""""""""""" + +- ``__rmatmul__`` + +Bitwise Operators +""""""""""""""""" + +- ``__rand__`` +- ``__ror__`` +- ``__rxor__`` +- ``__rlshift__`` +- ``__rrshift__`` + +------------------------------------------------- + +.. currentmodule:: signatures.array_object + +Attributes +---------- +.. + NOTE: please keep the attributes in alphabetical order + + +.. autosummary:: + :toctree: generated + + array.dtype + array.device + array.mT + array.ndim + array.shape + array.size + array.T + +------------------------------------------------- + +Methods +------- +.. + NOTE: please keep the methods in alphabetical order + + +.. autosummary:: + :toctree: generated + + array.__abs__ + array.__add__ + array.__and__ + array.__array_namespace__ + array.__bool__ + array.__dlpack__ + array.__dlpack_device__ + array.__eq__ + array.__float__ + array.__floordiv__ + array.__ge__ + array.__getitem__ + array.__gt__ + array.__index__ + array.__int__ + array.__invert__ + array.__le__ + array.__lshift__ + array.__lt__ + array.__matmul__ + array.__mod__ + array.__mul__ + array.__ne__ + array.__neg__ + array.__or__ + array.__pos__ + array.__pow__ + array.__rshift__ + array.__setitem__ + array.__sub__ + array.__truediv__ + array.__xor__ + array.to_device diff --git a/spec/API_specification/signatures/_types.py b/spec/API_specification/signatures/_types.py index 6c0b5b85a..6e624d542 100644 --- a/spec/API_specification/signatures/_types.py +++ b/spec/API_specification/signatures/_types.py @@ -7,6 +7,7 @@ from dataclasses import dataclass from typing import Any, List, Literal, Optional, Sequence, Tuple, TypeVar, Union +from enum import Enum array = TypeVar('array') device = TypeVar('device') @@ -37,4 +38,4 @@ class iinfo_object: __all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', 'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', -'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object'] \ No newline at end of file +'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object', 'Enum'] \ No newline at end of file diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py new file mode 100644 index 000000000..0562a90b3 --- /dev/null +++ b/spec/API_specification/signatures/array_object.py @@ -0,0 +1,942 @@ +from ._types import array, dtype, device, Optional, Tuple, Union, Any, PyCapsule, Enum, ellipsis + +class array(): + def __init__(self) -> None: + """ + Initialize the attributes for the array object class. + """ + + self.dtype = None + """ + Data type of the array elements. + + Returns + ------- + out: dtype + array data type. + """ + + self.device = None + """ + Hardware device the array data resides on. + + Returns + ------- + out: device + a ``device`` object (see :ref:`device-support`). + """ + + self.mT = None + """ + Transpose of a matrix (or a stack of matrices). + + If an array instance has fewer than two dimensions, an error should be raised. + + Returns + ------- + out: array + array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape ``(..., M, N)``, the returned array must have shape ``(..., N, M)``). The returned array must have the same data type as the original array. + """ + + self.ndim = None + """ + Number of array dimensions (axes). + + Returns + ------- + out: int + number of array dimensions (axes). + """ + + self.shape = None + """ + Array dimensions. + + Returns + ------- + out: Tuple[Optional[int], ...] + array dimensions. An array dimension must be ``None`` if and only if a dimension is unknown. + + Notes + ----- + - For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; ``A[:, B > 0]``) and thus cannot be statically resolved without knowing array contents. + + - The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. + """ + + self.size = None + """ + Number of elements in an array. + + Returns + ------- + out: Optional[int] + number of elements in an array. The returned value must be ``None`` if and only if one or more array dimensions are unknown. + + Notes + ----- + - This must equal the product of the array's dimensions. + + - For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. + """ + + self.T = None + """ + Transpose of the array. + + The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. + + Returns + ------- + out: array + two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array.two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. + + Notes + ----- + - Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional ``permute_dims`` interface found in this specification. + """ + + def __abs__(self: array, /) -> array: + """ + Calculates the absolute value for each element of an array instance (i.e., the element-wise result has the same magnitude as the respective element but has positive sign). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise absolute value. The returned array must have the same data type as ``self``. + + Notes + ----- + - For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-abs`. + + **Special cases** + + For floating-point operands, let ``self`` equal ``x``. + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``-0``, the result is ``+0``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + """ + + def __add__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the sum for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance (augend array). Should have a numeric data type. + other: Union[int, float, array] + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - Floating-point addition is a commutative operation, but not always associative. + + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-add`. + + **Special cases** + + For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is ``-infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is a nonzero finite number, the result is ``x2_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. + - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. + """ + + def __and__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i & other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_and`. + """ + + def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> object: + """ + Returns an object that has all the array API functions on it. + + Parameters + ---------- + self: array + array instance. + api_version: Optional[str] + string representing the version of the array API specification to be returned, in ``'YYYY.MM'`` form, for example, ``'2020.10'``. If it is ``None``, it should return the namespace corresponding to latest version of the array API specification. If the given version is invalid or not implemented for the given module, an error should be raised. Default: ``None``. + + Returns + ------- + out: object + an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. + """ + + def __bool__(self: array, /) -> bool: + """ + Converts a zero-dimensional boolean array to a Python ``bool`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Must have a boolean data type. + + Returns + ------- + out: bool + a Python ``bool`` object representing the single element of the array. + """ + + def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: + """ + Exports the array for consumption by :ref:`function-from_dlpack` as a DLPack capsule. + + Parameters + ---------- + self: array + array instance. + stream: Optional[Union[int, Any]] + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be a positive integer or ``-1``. If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. + On CPU and other device types without streams, only ``None`` is accepted. + + For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for `stream` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + + **Note** + + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + + Device-specific notes: + + **CUDA** + + - ``None``: producer must assume the legacy default stream (default). + - ``1``: the legacy default stream. + - ``2``: the per-thread default stream. + - ``> 2``: stream number represented as a Python integer. + + ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. + + **ROCm** + + - ``None``: producer must assume the legacy default stream (default). + - ``0``: the default stream. + - ``> 2``: stream number represented as a Python integer. + + Using ``1`` and ``2`` is not supported. + + **Tip** + + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronization than necessary. + + Returns + ------- + capsule: PyCapsule + a DLPack capsule for the array. See :ref:`data-interchange` for details. + """ + + def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: + """ + Returns device type and device ID in DLPack format. Meant for use within :ref:`function-from_dlpack`. + + Parameters + ---------- + self: array + array instance. + + Returns + ------- + device: Tuple[Enum, int] + a tuple ``(device_type, device_id)`` in DLPack format. Valid device type enum members are: + + - ``CPU = 1`` + - ``CUDA = 2`` + - ``CPU_PINNED = 3`` + - ``OPENCL = 4`` + - ``VULKAN = 7`` + - ``METAL = 8`` + - ``VPI = 9`` + - ``ROCM = 10`` + """ + + def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + """ + Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-equal`. + """ + + def __float__(self: array, /) -> float: + """ + Converts a zero-dimensional floating-point array to a Python ``float`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Must have a floating-point data type. + + Returns + ------- + out: float + a Python ``float`` object representing the single element of the array instance. + """ + + def __floordiv__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i // other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-floor_divide`. + - Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + + **Special cases** + + For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to ``+infinity``) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + """ + + def __ge__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater_equal`. + """ + + def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: + """ + Returns ``self[key]``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + index key. + + Returns + ------- + out: array + an array containing the accessed value(s). The returned array must have the same data type as ``self``. + """ + + def __gt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater`. + """ + + def __index__(self: array, /) -> int: + """ + Converts a zero-dimensional integer array to a Python ``int`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Must have an integer data type. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + - This method is called to implement `operator.index() `_. See also `PEP 357 `_. + """ + + def __int__(self: array, /) -> int: + """ + Converts a zero-dimensional integer array to a Python ``int`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Must have an integer data type. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + """ + + def __invert__(self: array, /) -> array: + """ + Evaluates ``~self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as `self`. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_invert`. + """ + + def __le__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less_equal`. + """ + + def __lshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i << other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_left_shift`. + """ + + def __lt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less`. + """ + + def __matmul__(self: array, other: array, /) -> array: + """ + Computes the matrix product. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + other: array + other array. Should have a numeric data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + Returns + ------- + out: array + - if both ``self`` and ``other`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``self`` is a one-dimensional array having shape ``(K,)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + - The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + - Results must equal the results returned by the equivalent function :ref:`function-matmul`. + + **Raises** + + - if either ``self`` or ``other`` is a zero-dimensional array. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + """ + + def __mod__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-remainder`. + """ + + def __mul__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the product for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - Floating-point multiplication is not always associative due to finite precision. + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-multiply`. + + **Special cases** + + For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign, the result has a positive mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` and ``x2_i`` have different mathematical signs, the result has a negative mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - In the remaining cases, where neither ``infinity`` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + """ + + def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + """ + Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-not_equal`. + """ + + def __neg__(self: array, /) -> array: + """ + Evaluates ``-self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-negative`. + """ + + def __or__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i | other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_or`. + """ + + def __pos__(self: array, /) -> array: + """ + Evaluates ``+self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-positive`. + """ + + def __pow__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. + + Parameters + ---------- + self: array + array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + other: Union[int, float, array] + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-pow`. + + **Special cases** + + For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x2_i`` is ``-0``, the result is `1`, even if ``x1_i`` is ``NaN``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is not equal to ``0``, the result is ``NaN``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``+infinity``, the result is ``1``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``-infinity``, the result is ``1``. + - If ``x1_i`` is ``1`` and ``x2_i`` is not ``NaN``, the result is ``1``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is greater than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + """ + + def __rshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i >> other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_right_shift`. + """ + + def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: + """ + Sets ``self[key]`` to ``value``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + index key. + value: Union[int, float, bool, array] + value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). + + Notes + ----- + - Setting array values must not affect the data type of ``self``. + - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + """ + + def __sub__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the difference for each element of an array instance with the respective element of the array ``other``. The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). + + Parameters + ---------- + self: array + array instance (minuend array). Should have a numeric data type. + other: Union[int, float, array] + subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-subtract`. + """ + + def __truediv__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-divide`. + + **Special cases** + + For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is `NaN`. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + """ + + def __xor__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i ^ other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_xor`. + """ + + def to_device(self: array, device: device, /, *, stream: Optional[Union[int, Any]] = None) -> array: + """ + Copy the array from the device on which it currently resides to the specified ``device``. + + Parameters + ---------- + self: array + array instance. + device: device + a ``device`` object (see :ref:`device-support`). + stream: Optional[Union[int, Any]] + stream object to use during copy. In addition to the types supported in :meth:`array.__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. + + Returns + ------- + out: array + an array with the same data and data type as ``self`` and located on the specified ``device``. + + Notes + ----- + - If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. + """ \ No newline at end of file From 9bf66d6767a74320fe09189b3f1ce4737f01a195 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 14 Dec 2021 12:27:51 -0500 Subject: [PATCH 124/551] Remove warnings --- spec/API_specification/array_object.rst | 4 ++-- spec/purpose_and_scope.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index 33a6e9e86..8062ecd1c 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -182,7 +182,7 @@ An in-place operation must not change the data type or shape of the in-place arr An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1 = x1 + x2``. .. note:: -In-place operators must be supported as discussed in :ref:`copyview-mutability`. + In-place operators must be supported as discussed in :ref:`copyview-mutability`. Arithmetic Operators """""""""""""""""""" @@ -217,7 +217,7 @@ A conforming implementation of the array API standard must provide and support a The results of applying reflected operators must match their non-reflected equivalents. .. note:: -All operators for which ``array scalar`` is implemented must have an equivalent reflected operator implementation. + All operators for which ``array scalar`` is implemented must have an equivalent reflected operator implementation. Arithmetic Operators """""""""""""""""""" diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index a34208cff..6e19c02ea 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -318,7 +318,7 @@ namespace (e.g. `import package_name.array_api`). This has two issues though: To address both issues, a uniform way must be provided by a conforming implementation to access the API namespace, namely a [method on the array -object](method-__array_namespace__): +object](array.__array_namespace__): ``` xp = x.__array_namespace__() From a6daf310b0e78cb2398ea89d521a2dae1b765558 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 14 Dec 2021 15:07:17 -0500 Subject: [PATCH 125/551] Change redirecting github action --- .github/workflows/preview.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index cdb310fe4..4ca25be0e 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -14,6 +14,3 @@ jobs: artifact-path: 0/build/latest/index.html circleci-jobs: build_page job-title: Check the rendered docs here! - - name: Array API preview - run: | - curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA From d81ebe2787afe893cc1d576655ce8cc53ea1811a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 14 Dec 2021 15:25:00 -0500 Subject: [PATCH 126/551] Revert changes --- .github/workflows/preview.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 4ca25be0e..d15d99107 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -14,3 +14,6 @@ jobs: artifact-path: 0/build/latest/index.html circleci-jobs: build_page job-title: Check the rendered docs here! + - name: Array API preview + run: | + curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA \ No newline at end of file From 1850abe1c73f64e688c5277af7b96be46017491f Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 15 Dec 2021 12:07:50 -0500 Subject: [PATCH 127/551] Transform broadcasting.md to .rst --- spec/API_specification/boradcasting.rst | 118 ++++++++++++++++++++++++ spec/API_specification/broadcasting.md | 116 ----------------------- 2 files changed, 118 insertions(+), 116 deletions(-) create mode 100644 spec/API_specification/boradcasting.rst delete mode 100644 spec/API_specification/broadcasting.md diff --git a/spec/API_specification/boradcasting.rst b/spec/API_specification/boradcasting.rst new file mode 100644 index 000000000..3692691d2 --- /dev/null +++ b/spec/API_specification/boradcasting.rst @@ -0,0 +1,118 @@ +Broadcasting +============ + + Array API specification for broadcasting semantics. + +Overview +-------- + +**Broadcasting** refers to the automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +Broadcasting facilitates user ergonomics by encouraging users to avoid unnecessary copying of array data and can **potentially** enable more memory-efficient element-wise operations through vectorization, reduced memory consumption, and cache locality. + +Algorithm +--------- + +Given an element-wise operation involving two compatible arrays, an array having a singleton dimension (i.e., a dimension whose size is one) is broadcast (i.e., virtually repeated) across an array having a corresponding non-singleton dimension. + +If two arrays are of unequal rank, the array having a lower rank is promoted to a higher rank by (virtually) prepending singleton dimensions until the number of dimensions matches that of the array having a higher rank. + +The results of the element-wise operation must be stored in an array having a shape determined by the following algorithm. + +1. Let ``A`` and ``B`` both be arrays. + +1. Let ``shape1`` be a tuple describing the shape of array ``A``. + +1. Let ``shape2`` be a tuple describing the shape of array ``B``. + +1. Let ``N1`` be the number of dimensions of array ``A`` (i.e., the result of ``len(shape1)``). + +1. Let ``N2`` be the number of dimensions of array ``B`` (i.e., the result of ``len(shape2)``). + +1. Let ``N`` be the maximum value of ``N1`` and ``N2`` (i.e., the result of ``max(N1, N2)``). + +1. Let ``shape`` be a temporary list of length ``N`` for storing the shape of the result array. + +1. Let ``i`` be ``N-1``. + +1. Repeat, while ``i >= 0`` + + 1. Let ``n1`` be ``N1 - N + i``. + + 1. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. + + 1. Let ``n2`` be ``N2 - N + i``. + + 1. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. + + 1. If ``d1 == 1``, then + + - set the ``i``th element of ``shape`` to ``d2``. + + 1. Else, if ``d2 == 1``, then + + - set the ``i``th element of ``shape`` to ``d1``. + + 1. Else, if ``d1 == d2``, then + + - set the ``i``th element of ``shape`` to ``d1``. + + 1. Else, throw an exception. + + 1. Set ``i`` to ``i-1``. + +1. Let ``tuple(shape)`` be the shape of the result array. + +Examples +~~~~~~~~ + +The following examples demonstrate the application of the broadcasting algorithm for two compatible arrays. + +:: + A (4d array): 8 x 1 x 6 x 1 + B (3d array): 7 x 1 x 5 + --------------------------------- + Result (4d array): 8 x 7 x 6 x 5 + + A (2d array): 5 x 4 + B (1d array): 1 + ------------------------- + Result (2d array): 5 x 4 + + A (2d array): 5 x 4 + B (1d array): 4 + ------------------------- + Result (2d array): 5 x 4 + + A (3d array): 15 x 3 x 5 + B (3d array): 15 x 1 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 1 + ------------------------------ + Result (3d array): 15 x 3 x 5 + + +The following examples demonstrate array shapes which do **not** broadcast. + +:: + A (1d array): 3 + B (1d array): 4 # dimension does not match + + A (2d array): 2 x 1 + B (3d array): 8 x 4 x 3 # second dimension does not match + + A (3d array): 15 x 3 x 5 + B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended + +In-place Semantics +------------------ + +As implied by the broadcasting algorithm, in-place element-wise operations must not change the shape of the in-place array as a result of broadcasting. \ No newline at end of file diff --git a/spec/API_specification/broadcasting.md b/spec/API_specification/broadcasting.md deleted file mode 100644 index 34e90cd0b..000000000 --- a/spec/API_specification/broadcasting.md +++ /dev/null @@ -1,116 +0,0 @@ -(broadcasting)= - -# Broadcasting - -> Array API specification for broadcasting semantics. - -## Overview - -**Broadcasting** refers to the automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. - -Broadcasting facilitates user ergonomics by encouraging users to avoid unnecessary copying of array data and can **potentially** enable more memory-efficient element-wise operations through vectorization, reduced memory consumption, and cache locality. - -## Algorithm - -Given an element-wise operation involving two compatible arrays, an array having a singleton dimension (i.e., a dimension whose size is one) is broadcast (i.e., virtually repeated) across an array having a corresponding non-singleton dimension. - -If two arrays are of unequal rank, the array having a lower rank is promoted to a higher rank by (virtually) prepending singleton dimensions until the number of dimensions matches that of the array having a higher rank. - -The results of the element-wise operation must be stored in an array having a shape determined by the following algorithm. - -1. Let `A` and `B` both be arrays. - -1. Let `shape1` be a tuple describing the shape of array `A`. - -1. Let `shape2` be a tuple describing the shape of array `B`. - -1. Let `N1` be the number of dimensions of array `A` (i.e., the result of `len(shape1)`). - -1. Let `N2` be the number of dimensions of array `B` (i.e., the result of `len(shape2)`). - -1. Let `N` be the maximum value of `N1` and `N2` (i.e., the result of `max(N1, N2)`). - -1. Let `shape` be a temporary list of length `N` for storing the shape of the result array. - -1. Let `i` be `N-1`. - -1. Repeat, while `i >= 0` - - 1. Let `n1` be `N1 - N + i`. - - 1. If `n1 >= 0`, let `d1` be the size of dimension `n1` for array `A` (i.e., the result of `shape1[n1]`); else, let `d1` be `1`. - - 1. Let `n2` be `N2 - N + i`. - - 1. If `n2 >= 0`, let `d2` be the size of dimension `n2` for array `B` (i.e., the result of `shape2[n2]`); else, let `d2` be `1`. - - 1. If `d1 == 1`, then - - - set the `i`th element of `shape` to `d2`. - - 1. Else, if `d2 == 1`, then - - - set the `i`th element of `shape` to `d1`. - - 1. Else, if `d1 == d2`, then - - - set the `i`th element of `shape` to `d1`. - - 1. Else, throw an exception. - - 1. Set `i` to `i-1`. - -1. Let `tuple(shape)` be the shape of the result array. - -### Examples - -The following examples demonstrate the application of the broadcasting algorithm for two compatible arrays. - -```text -A (4d array): 8 x 1 x 6 x 1 -B (3d array): 7 x 1 x 5 ---------------------------------- -Result (4d array): 8 x 7 x 6 x 5 - -A (2d array): 5 x 4 -B (1d array): 1 -------------------------- -Result (2d array): 5 x 4 - -A (2d array): 5 x 4 -B (1d array): 4 -------------------------- -Result (2d array): 5 x 4 - -A (3d array): 15 x 3 x 5 -B (3d array): 15 x 1 x 5 ------------------------------- -Result (3d array): 15 x 3 x 5 - -A (3d array): 15 x 3 x 5 -B (2d array): 3 x 5 ------------------------------- -Result (3d array): 15 x 3 x 5 - -A (3d array): 15 x 3 x 5 -B (2d array): 3 x 1 ------------------------------- -Result (3d array): 15 x 3 x 5 -``` - -The following examples demonstrate array shapes which do **not** broadcast. - -```text -A (1d array): 3 -B (1d array): 4 # dimension does not match - -A (2d array): 2 x 1 -B (3d array): 8 x 4 x 3 # second dimension does not match - -A (3d array): 15 x 3 x 5 -B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended -``` - -## In-place Semantics - -As implied by the broadcasting algorithm, in-place element-wise operations must not change the shape of the in-place array as a result of broadcasting. \ No newline at end of file From 103a8fbd437170a579cedaa844c30db6e1c38ce8 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 15 Dec 2021 12:22:18 -0500 Subject: [PATCH 128/551] Transform constants.md to rst format --- spec/API_specification/constants.md | 39 ------------------- spec/API_specification/constants.rst | 24 ++++++++++++ .../API_specification/signatures/constants.py | 25 ++++++++++++ 3 files changed, 49 insertions(+), 39 deletions(-) delete mode 100644 spec/API_specification/constants.md create mode 100644 spec/API_specification/constants.rst create mode 100644 spec/API_specification/signatures/constants.py diff --git a/spec/API_specification/constants.md b/spec/API_specification/constants.md deleted file mode 100644 index 78cdc8de7..000000000 --- a/spec/API_specification/constants.md +++ /dev/null @@ -1,39 +0,0 @@ -# Constants - -> Array API specification for constants. - -A conforming implementation of the array API standard must provide and support the following constants adhering to the following conventions. - -- Each constant must have a Python floating-point data type (i.e., `float`) and be provided as a Python scalar value. - - - -## Objects in API - -(constant-e)= -### e - -IEEE 754 floating-point representation of Euler's constant. - -```text -e = 2.71828182845904523536028747135266249775724709369995... -``` - -(constant-inf)= -### inf - -IEEE 754 floating-point representation of (positive) infinity. - -(constant-nan)= -### nan - -IEEE 754 floating-point representation of Not a Number (`NaN`). - -(constant-pi)= -### pi - -IEEE 754 floating-point representation of the mathematical constant `π`. - -```text -pi = 3.1415926535897932384626433... -``` diff --git a/spec/API_specification/constants.rst b/spec/API_specification/constants.rst new file mode 100644 index 000000000..eab159c9d --- /dev/null +++ b/spec/API_specification/constants.rst @@ -0,0 +1,24 @@ +Constants +========= + + Array API specification for constants. + +A conforming implementation of the array API standard must provide and support the following constants adhering to the following conventions. + +- Each constant must have a Python floating-point data type (i.e., ``float``) and be provided as a Python scalar value. + +Objects in API +-------------- + +.. currentmodule:: signatures.constants + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + + e + inf + nan + pi diff --git a/spec/API_specification/signatures/constants.py b/spec/API_specification/signatures/constants.py new file mode 100644 index 000000000..069f10005 --- /dev/null +++ b/spec/API_specification/signatures/constants.py @@ -0,0 +1,25 @@ +e = None +""" +IEEE 754 floating-point representation of Euler's constant. + +``e = 2.71828182845904523536028747135266249775724709369995...`` +""" + +inf = None +""" +IEEE 754 floating-point representation of (positive) infinity. +""" + +nan = None +""" +IEEE 754 floating-point representation of Not a Number (``NaN``). +""" + +pi = None +""" +IEEE 754 floating-point representation of the mathematical constant ``π``. + +``pi = 3.1415926535897932384626433...`` +""" + +__all__ = ['e', 'inf', 'nan', 'pi'] From 13a0dd532951be651f986ab1a210869512687bde Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 15 Dec 2021 12:37:06 -0500 Subject: [PATCH 129/551] Fix typo and warnings --- spec/API_specification/{boradcasting.rst => broadcasting.rst} | 2 ++ 1 file changed, 2 insertions(+) rename spec/API_specification/{boradcasting.rst => broadcasting.rst} (99%) diff --git a/spec/API_specification/boradcasting.rst b/spec/API_specification/broadcasting.rst similarity index 99% rename from spec/API_specification/boradcasting.rst rename to spec/API_specification/broadcasting.rst index 3692691d2..b930aaa12 100644 --- a/spec/API_specification/boradcasting.rst +++ b/spec/API_specification/broadcasting.rst @@ -1,3 +1,5 @@ +.. _broadcasting: + Broadcasting ============ From 2f53fdeade62807a04912c0868c594a1d8955cb3 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 21 Dec 2021 19:03:21 -0500 Subject: [PATCH 130/551] convert creation functions into rst --- spec/API_specification/creation_functions.md | 501 ------------------ spec/API_specification/creation_functions.rst | 38 ++ spec/API_specification/signatures/_types.py | 2 +- .../signatures/creation_functions.py | 383 +++++++++++++ 4 files changed, 422 insertions(+), 502 deletions(-) delete mode 100644 spec/API_specification/creation_functions.md create mode 100644 spec/API_specification/creation_functions.rst create mode 100644 spec/API_specification/signatures/creation_functions.py diff --git a/spec/API_specification/creation_functions.md b/spec/API_specification/creation_functions.md deleted file mode 100644 index a4b4e7d99..000000000 --- a/spec/API_specification/creation_functions.md +++ /dev/null @@ -1,501 +0,0 @@ -# Creation Functions - -> Array API specification for creating 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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) arguments. - -## Objects in API - - - -(function-arange)= -### arange(start, /, stop=None, step=1, *, dtype=None, device=None) - -Returns evenly spaced values within the half-open interval `[start, stop)` as a one-dimensional array. - -#### Parameters - -- **start**: _Union\[ int, float ]_ - - - if `stop` is specified, the start of interval (inclusive); otherwise, the end of the interval (exclusive). If `stop` is not specified, the default starting value is `0`. - -- **stop**: _Optional\[ Union\[ int, float ] ]_ - - - the end of the interval. Default: `None`. - -```{note} - -This function cannot guarantee that the interval does not include the `stop` value in those cases where `step` is not an integer and floating-point rounding errors affect the length of the output array. -``` - -- **step**: _Union\[ int, float ]_ - - - the distance between two adjacent elements (`out[i+1] - out[i]`). Must not be `0`; may be negative, this results in an empty array if `stop >= start`. Default: `1`. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `start`, `stop` and `step`. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type `float`, then the output array dtype must be the default floating-point data type. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - a one-dimensional array containing evenly spaced values. The length of the output array must be `ceil((stop-start)/step)` if `stop - start` and `step` have the same sign, and length 0 otherwise. - - -(function-asarray)= -### asarray(obj, /, *, dtype=None, device=None, copy=None) - -Convert the input to an array. - -#### Parameters - -- **obj**: _Union\[ <array>, bool, int, float, NestedSequence\[ bool | int | float ], SupportsBufferProtocol ]_ - - - object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. - - :::{tip} - An object supporting the buffer protocol can be turned into a memoryview through `memoryview(obj)`. - ::: - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be inferred from the data type(s) in `obj`. If all input values are Python scalars, then - - - if all values are of type `bool`, the output data type must be `bool`. - - if the values are a mixture of `bool`s and `int`, the output data type must be the default integer data type. - - if one or more values are `float`s, the output data type must be the default floating-point data type. - - Default: `None`. - - ```{note} - If `dtype` is not `None`, then array conversions should obey {ref}`type-promotion` rules. Conversions not specified according to {ref}`type-promotion` rules may or may not be permitted by a conforming array library. - - To perform an explicit cast, use {ref}`function-astype`. - ``` - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. If `device` is `None` and `x` is an array, the output array device must be inferred from `x`. Default: `None`. - -- **copy**: _Optional\[ bool ]_ - - - boolean indicating whether or not to copy the input. If `True`, the function must always copy. If `False`, the function must never copy for input which supports the buffer protocol and must raise a `ValueError` in case a copy would be necessary. If `None`, the function must reuse existing memory buffer if possible and copy otherwise. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the data from `obj`. - -(function-empty)= -### empty(shape, *, dtype=None, device=None) - -Returns an uninitialized array having a specified `shape`. - -#### Parameters - -- **shape**: _Union\[ int, Tuple\[ int, ... ] ]_ - - - output array shape. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be the default floating-point data type. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing uninitialized data. - -(function-empty_like)= -### empty_like(x, /, *, dtype=None, device=None) - -Returns an uninitialized array with the same `shape` as an input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array from which to derive the output array shape. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `x`. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array having the same shape as `x` and containing uninitialized data. - -(function-eye)= -### eye(n_rows, n_cols=None, /, *, k=0, dtype=None, device=None) - -Returns a two-dimensional array with ones on the `k`th diagonal and zeros elsewhere. - -#### Parameters - -- **n_rows**: _int_ - - - number of rows in the output array. - -- **n_cols**: _Optional\[ int ]_ - - - number of columns in the output array. If `None`, the default number of columns in the output array is equal to `n_rows`. Default: `None`. - -- **k**: _int_ - - - index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and `0` to the main diagonal. Default: `0`. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be the default floating-point data type. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array where all elements are equal to zero, except for the `k`th diagonal, whose values are equal to one. - -(function-from_dlpack)= -### from_dlpack(x, /) - -Returns a new array containing the data from another (array) object with a `__dlpack__` method. - -#### Parameters - -- **x**: _object_ - - - input (array) object. - -#### Returns - -- **out**: _<array>_ - - - an array containing the data in `x`. - - ```{note} - The returned array may be either a copy or a view. See {ref}`data-interchange` for details. - ``` - -(function-full)= -### full(shape, fill_value, *, dtype=None, device=None) - -Returns a new array having a specified `shape` and filled with `fill_value`. - -#### Parameters - -- **shape**: _Union\[ int, Tuple\[ int, ... ] ]_ - - - output array shape. - -- **fill_value**: _Union\[ int, float ]_ - - - fill value. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `fill_value`. If the fill value is an `int`, the output array data type must be the default integer data type. If the fill value is a `float`, the output array data type must be the default floating-point data type. If the fill value is a `bool`, the output array must have boolean data type. Default: `None`. - - ```{note} - If `dtype` is `None` and the `fill_value` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. - ``` - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array where every element is equal to `fill_value`. - -(function-full_like)= -### full_like(x, /, fill_value, *, dtype=None, device=None) - -Returns a new array filled with `fill_value` and having the same `shape` as an input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array from which to derive the output array shape. - -- **fill_value**: _Union\[ int, float ]_ - - - fill value. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `x`. Default: `None`. - - ```{note} - If `dtype` is `None` and the `fill_value` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. - ``` - - ```{note} - If `dtype` is `None` and the `fill_value` has a data type (`int` or `float`) which is not of the same data type kind as the resolved output array data type (see {ref}`type-promotion`), behavior is unspecified and, thus, implementation-defined. - ``` - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array having the same shape as `x` and where every element is equal to `fill_value`. - -(function-linspace)= -### linspace(start, stop, /, num, *, dtype=None, device=None, endpoint=True) - -Returns evenly spaced numbers over a specified interval. - -#### Parameters - -- **start**: _Union\[ int, float ]_ - - - the start of the interval. - -- **stop**: _Union\[ int, float ]_ - - - the end of the interval. If `endpoint` is `False`, the function must generate a sequence of `num+1` evenly spaced numbers starting with `start` and ending with `stop` and exclude the `stop` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval `[start, stop)`. If `endpoint` is `True`, the output array must consist of evenly spaced numbers over the closed interval `[start, stop]`. Default: `True`. - - ```{note} - - The step size changes when `endpoint` is `False`. - ``` - -- **num**: _int_ - - - number of samples. Must be a non-negative integer value; otherwise, the function must raise an exception. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be the default floating-point data type. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. Default: `None`. - -- **endpoint**: _bool_ - - - boolean indicating whether to include `stop` in the interval. Default: `True`. - -#### Returns - -- **out**: _<array>_ - - - a one-dimensional array containing evenly spaced values. - -(function-meshgrid)= -### meshgrid(*arrays, indexing='xy') - -Returns coordinate matrices from coordinate vectors. - -#### Parameters - -- **arrays**: _<array>_ - - - an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - -- **indexing**: _str_ - - - Cartesian 'xy' or matrix 'ij' indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the `indexing` keyword has no effect and should be ignored. Default: `'xy'`. - -#### Returns - -- **out**: _List\[ <array>, ... ]_ - - - list of N arrays, where `N` is the number of provided one-dimensional input arrays. Each returned array must have rank `N`. For `N` one-dimensional arrays having lengths `Ni = len(xi)`, - - - if matrix indexing `ij`, then each returned array must have the shape `(N1, N2, N3, ..., Nn)`. - - - if Cartesian indexing `xy`, then each returned array must have shape `(N2, N1, N3, ..., Nn)`. - - Accordingly, for the two-dimensional case with input one-dimensional arrays of length `M` and `N`, if matrix indexing `ij`, then each returned array must have shape `(M, N)`, and, if Cartesian indexing `xy`, then each returned array must have shape `(N, M)`. - - Similarly, for the three-dimensional case with input one-dimensional arrays of length `M`, `N`, and `P`, if matrix indexing `ij`, then each returned array must have shape `(M, N, P)`, and, if Cartesian indexing `xy`, then each returned array must have shape `(N, M, P)`. - - Each returned array should have the same data type as the input arrays. - -(function-ones)= -### ones(shape, *, dtype=None, device=None) - -Returns a new array having a specified `shape` and filled with ones. - -#### Parameters - -- **shape**: _Union\[ int, Tuple\[ int, ... ] ]_ - - - output array shape. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be the default floating-point data type. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing ones. - -(function-ones_like)= -### ones_like(x, /, *, dtype=None, device=None) - -Returns a new array filled with ones and having the same `shape` as an input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array from which to derive the output array shape. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `x`. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array having the same shape as `x` and filled with ones. - -(function-tril)= -### tril(x, /, *, k=0) - -Returns the lower triangular part of a matrix (or a stack of matrices) `x`. - -```{note} -The lower triangular part of the matrix is defined as the elements on and below the specified diagonal `k`. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. - -- **k**: _int_ - - - diagonal above which to zero elements. If `k = 0`, the diagonal is the main diagonal. If `k < 0`, the diagonal is below the main diagonal. If `k > 0`, the diagonal is above the main diagonal. Default: `0`. - - ```{note} - The main diagonal is defined as the set of indices `{(i, i)}` for `i` on the interval `[0, min(M, N) - 1]`. - ``` - -#### Returns - -- **out**: _<array>_ - - - an array containing the lower triangular part(s). The returned array must have the same shape and data type as `x`. All elements above the specified diagonal `k` must be zeroed. The returned array should be allocated on the same device as `x`. - -(function-triu)= -### triu(x, /, *, k=0) - -Returns the upper triangular part of a matrix (or a stack of matrices) `x`. - -```{note} -The upper triangular part of the matrix is defined as the elements on and above the specified diagonal `k`. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. - -- **k**: _int_ - - - diagonal below which to zero elements. If `k = 0`, the diagonal is the main diagonal. If `k < 0`, the diagonal is below the main diagonal. If `k > 0`, the diagonal is above the main diagonal. Default: `0`. - - ```{note} - The main diagonal is defined as the set of indices `{(i, i)}` for `i` on the interval `[0, min(M, N) - 1]`. - ``` - -#### Returns - -- **out**: _<array>_ - - - an array containing the upper triangular part(s). The returned array must have the same shape and data type as `x`. All elements below the specified diagonal `k` must be zeroed. The returned array should be allocated on the same device as `x`. - -(function-zeros)= -### zeros(shape, *, dtype=None, device=None) - -Returns a new array having a specified `shape` and filled with zeros. - -#### Parameters - -- **shape**: _Union\[ int, Tuple\[ int, ... ] ]_ - - - output array shape. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be the default floating-point data type. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing zeros. - -(function-zeros_like)= -### zeros_like(x, /, *, dtype=None, device=None) - -Returns a new array filled with zeros and having the same `shape` as an input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array from which to derive the output array shape. - -- **dtype**: _Optional\[ <dtype> ]_ - - - output array data type. If `dtype` is `None`, the output array data type must be inferred from `x`. Default: `None`. - -- **device**: _Optional\[ <device> ]_ - - - device on which to place the created array. If `device` is `None`, the output array device must be inferred from `x`. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array having the same shape as `x` and filled with zeros. diff --git a/spec/API_specification/creation_functions.rst b/spec/API_specification/creation_functions.rst new file mode 100644 index 000000000..c34f67378 --- /dev/null +++ b/spec/API_specification/creation_functions.rst @@ -0,0 +1,38 @@ +Creation Functions +================== + + Array API specification for creating 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. + +Objects in API +-------------- + +.. currentmodule:: signatures.creation_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + arange + asarray + empty + empty_like + eye + from_dlpack + full + full_like + linspace + meshgrid + ones + ones_like + tril + triu + zeros + zeros_like diff --git a/spec/API_specification/signatures/_types.py b/spec/API_specification/signatures/_types.py index 6c0b5b85a..99001e470 100644 --- a/spec/API_specification/signatures/_types.py +++ b/spec/API_specification/signatures/_types.py @@ -33,7 +33,7 @@ class iinfo_object: min: int # This should really be recursive, but that isn't supported yet. -NestedSequence = Sequence[Sequence[Any]] +NestedSequence = Sequence[Any] __all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', 'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py new file mode 100644 index 000000000..afc2bba05 --- /dev/null +++ b/spec/API_specification/signatures/creation_functions.py @@ -0,0 +1,383 @@ +from ._types import (List, NestedSequence, Optional, SupportsBufferProtocol, Tuple, Union, array, + device, dtype) + +def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None, step: Union[int, float] = 1, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. + + Parameters + ---------- + start: Union[int, float] + if ``stop`` is specified, the start of interval (inclusive); otherwise, the end of the interval (exclusive). If ``stop`` is not specified, the default starting value is ``0``. + stop: Optional[Union[int, float]] + the end of the interval. Default: ``None``. + step: Union[int, float] + the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. + + Notes + ----- + - This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. + """ + +def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: + """ + Convert the input to an array. + + Parameters + ---------- + obj: Union[array, bool, int, float, NestedSequence[bool | int | float], SupportsBufferProtocol] + object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. + + **Tip** + + An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then + + - if all values are of type ``bool``, the output data type must be ``bool``. + - if the values are a mixture of ``bool``s and ``int``, the output data type must be the default integer data type. + - if one or more values are ``float``s, the output data type must be the default floating-point data type. + + Default: ``None``. + + **Note** + + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. + To perform an explicit cast, use :ref:`function-astype`. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data from ``obj``. + """ + +def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns an uninitialized array having a specified `shape`. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing uninitialized data. + """ + +def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns an uninitialized array with the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and containing uninitialized data. + """ + +def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns a two-dimensional array with ones on the ``k``th diagonal and zeros elsewhere. + + Parameters + ---------- + n_rows: int + number of rows in the output array. + n_cols: Optional[int] + number of columns in the output array. If ``None``, the default number of columns in the output array is equal to ``n_rows``. Default: ``None``. + k: int + index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and ``0`` to the main diagonal. Default: ``0``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where all elements are equal to zero, except for the ``k``th diagonal, whose values are equal to one. + """ + +def from_dlpack(x: object, /) -> array: + """ + Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. + + Parameters + ---------- + x: object + input (array) object. + + Returns + ------- + out: array + an array containing the data in `x`. + + Notes + ----- + - The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + """ + +def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ``fill_value``. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + fill_value: Union[int, float] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value``. If the fill value is an ``int``, the output array data type must be the default integer data type. If the fill value is a ``float``, the output array data type must be the default floating-point data type. If the fill value is a ``bool``, the output array must have boolean data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where every element is equal to ``fill_value``. + + Notes + ----- + - If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + """ + +def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + fill_value: Union[int, float] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + - If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + - If ``dtype`` is ``None`` and the ``fill_value`` has a data type (``int`` or ``float``) which is not of the same data type kind as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + """ + +def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, dtype: Optional[dtype] = None, device: Optional[device] = None, endpoint: bool = True) -> array: + """ + Returns evenly spaced numbers over a specified interval. + + Parameters + ---------- + start: Union[int, float] + the start of the interval. + stop: Union[int, float] + the end of the interval. If ``endpoint`` is ``False``, the function must generate a sequence of ``num+1`` evenly spaced numbers starting with ``start`` and ending with ``stop`` and exclude the ``stop`` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval ``[start, stop)``. If ``endpoint`` is ``True``, the output array must consist of evenly spaced numbers over the closed interval ``[start, stop]``. Default: ``True``. + num: int + number of samples. Must be a non-negative integer value; otherwise, the function must raise an exception. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + endpoint: bool + boolean indicating whether to include ``stop`` in the interval. Default: ``True``. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. + + Notes + ----- + - The step size changes when `endpoint` is `False`. + """ + +def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: + """ + Returns coordinate matrices from coordinate vectors. + + Parameters + ---------- + arrays: array + an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. + indexing: str + Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. + + Returns + ------- + out: List[array] + list of N arrays, where ``N`` is the number of provided one-dimensional input arrays. Each returned array must have rank ``N``. For ``N`` one-dimensional arrays having lengths ``Ni = len(xi)``, + + - if matrix indexing ``ij``, then each returned array must have the shape ``(N1, N2, N3, ..., Nn)``. + - if Cartesian indexing ``xy``, then each returned array must have shape ``(N2, N1, N3, ..., Nn)``. + + Accordingly, for the two-dimensional case with input one-dimensional arrays of length ``M`` and ``N``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M)``. + + Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. + + Each returned array should have the same data type as the input arrays. + """ + +def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ones. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing ones. + """ + +def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with ones. + """ + +def tril(x: array, /, *, k: int = 0) -> array: + """ + Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal above which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + Returns + ------- + out: array + an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + + Notes + ----- + - The lower triangular part of the matrix is defined as the elements on and below the specified diagonal ``k``. + - The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + """ + +def triu(x: array, /, *, k: int = 0) -> array: + """ + Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal below which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + Returns + ------- + out: array + an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + + Notes + ----- + - The upper triangular part of the matrix is defined as the elements on and above the specified diagonal ``k``. + - The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + """ + +def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns a new array having a specified `shape` and filled with zeros. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing zeros. + """ + +def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + """ + Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with zeros. + """ + +def test(): + """ + Parameters + ---------- + + Returns + ------- + + Notes + ----- + """ \ No newline at end of file From 8faf1a6983e136db6e7f193813570685fab110a4 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 21 Dec 2021 19:09:40 -0500 Subject: [PATCH 131/551] Add missing template to toctree --- spec/API_specification/array_object.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index 8062ecd1c..ecbd91861 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -256,6 +256,7 @@ Attributes .. autosummary:: :toctree: generated + :template: method.rst array.dtype array.device @@ -275,6 +276,7 @@ Methods .. autosummary:: :toctree: generated + :template: method.rst array.__abs__ array.__add__ From 503cf825ea0e768ad395d3774f5fd82bd84bfff2 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 21 Dec 2021 19:13:51 -0500 Subject: [PATCH 132/551] Fix warnings --- spec/API_specification/array_object.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index ecbd91861..8062ecd1c 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -256,7 +256,6 @@ Attributes .. autosummary:: :toctree: generated - :template: method.rst array.dtype array.device @@ -276,7 +275,6 @@ Methods .. autosummary:: :toctree: generated - :template: method.rst array.__abs__ array.__add__ From 115b82caad9a2922ebec487581ca0d61c5b64d21 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 21 Dec 2021 19:20:29 -0500 Subject: [PATCH 133/551] Fix ordered lists --- spec/API_specification/broadcasting.rst | 40 ++++++++++++------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/spec/API_specification/broadcasting.rst b/spec/API_specification/broadcasting.rst index b930aaa12..8b55e5e70 100644 --- a/spec/API_specification/broadcasting.rst +++ b/spec/API_specification/broadcasting.rst @@ -21,49 +21,49 @@ If two arrays are of unequal rank, the array having a lower rank is promoted to The results of the element-wise operation must be stored in an array having a shape determined by the following algorithm. -1. Let ``A`` and ``B`` both be arrays. +#. Let ``A`` and ``B`` both be arrays. -1. Let ``shape1`` be a tuple describing the shape of array ``A``. +#. Let ``shape1`` be a tuple describing the shape of array ``A``. -1. Let ``shape2`` be a tuple describing the shape of array ``B``. +#. Let ``shape2`` be a tuple describing the shape of array ``B``. -1. Let ``N1`` be the number of dimensions of array ``A`` (i.e., the result of ``len(shape1)``). +#. Let ``N1`` be the number of dimensions of array ``A`` (i.e., the result of ``len(shape1)``). -1. Let ``N2`` be the number of dimensions of array ``B`` (i.e., the result of ``len(shape2)``). +#. Let ``N2`` be the number of dimensions of array ``B`` (i.e., the result of ``len(shape2)``). -1. Let ``N`` be the maximum value of ``N1`` and ``N2`` (i.e., the result of ``max(N1, N2)``). +#. Let ``N`` be the maximum value of ``N1`` and ``N2`` (i.e., the result of ``max(N1, N2)``). -1. Let ``shape`` be a temporary list of length ``N`` for storing the shape of the result array. +#. Let ``shape`` be a temporary list of length ``N`` for storing the shape of the result array. -1. Let ``i`` be ``N-1``. +#. Let ``i`` be ``N-1``. -1. Repeat, while ``i >= 0`` +#. Repeat, while ``i >= 0`` - 1. Let ``n1`` be ``N1 - N + i``. + #. Let ``n1`` be ``N1 - N + i``. - 1. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. + #. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. - 1. Let ``n2`` be ``N2 - N + i``. + #. Let ``n2`` be ``N2 - N + i``. - 1. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. + #. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. - 1. If ``d1 == 1``, then + #. If ``d1 == 1``, then - set the ``i``th element of ``shape`` to ``d2``. - 1. Else, if ``d2 == 1``, then + #. Else, if ``d2 == 1``, then - set the ``i``th element of ``shape`` to ``d1``. - 1. Else, if ``d1 == d2``, then + #. Else, if ``d1 == d2``, then - set the ``i``th element of ``shape`` to ``d1``. - 1. Else, throw an exception. + #. Else, throw an exception. - 1. Set ``i`` to ``i-1``. + #. Set ``i`` to ``i-1``. -1. Let ``tuple(shape)`` be the shape of the result array. +#. Let ``tuple(shape)`` be the shape of the result array. Examples ~~~~~~~~ @@ -117,4 +117,4 @@ The following examples demonstrate array shapes which do **not** broadcast. In-place Semantics ------------------ -As implied by the broadcasting algorithm, in-place element-wise operations must not change the shape of the in-place array as a result of broadcasting. \ No newline at end of file +As implied by the broadcasting algorithm, in-place element-wise operations must not change the shape of the in-place array as a result of broadcasting. From 337243a474af3c0b36076c89bf27f012d78e59b4 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 21 Dec 2021 23:00:51 -0500 Subject: [PATCH 134/551] Remove unused function --- .../signatures/creation_functions.py | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index afc2bba05..928c58ade 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -369,15 +369,3 @@ def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d out: array an array having the same shape as ``x`` and filled with zeros. """ - -def test(): - """ - Parameters - ---------- - - Returns - ------- - - Notes - ----- - """ \ No newline at end of file From 5d24ef34299d5adc27520ba5f42b0e60bf8cc6f8 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 22 Dec 2021 15:59:09 -0500 Subject: [PATCH 135/551] Transform data_types.md to rst --- spec/API_specification/data_types.md | 165 ------------------ spec/API_specification/data_types.rst | 163 +++++++++++++++++ .../signatures/data_types.py | 20 +++ 3 files changed, 183 insertions(+), 165 deletions(-) delete mode 100644 spec/API_specification/data_types.md create mode 100644 spec/API_specification/data_types.rst create mode 100644 spec/API_specification/signatures/data_types.py diff --git a/spec/API_specification/data_types.md b/spec/API_specification/data_types.md deleted file mode 100644 index de4798b41..000000000 --- a/spec/API_specification/data_types.md +++ /dev/null @@ -1,165 +0,0 @@ -(data-types)= - -# Data Types - -> Array API specification for supported data types. - -A conforming implementation of the array API standard must provide and support the following data types. - -## bool - -Boolean (`True` or `False`). - -## int8 - -An 8-bit signed integer whose values exist on the interval `[-128, +127]`. - -## int16 - -A 16-bit signed integer whose values exist on the interval `[−32,767, +32,767]`. - -## int32 - -A 32-bit signed integer whose values exist on the interval `[−2,147,483,647, +2,147,483,647]`. - -## int64 - -A 64-bit signed integer whose values exist on the interval `[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]`. - -## uint8 - -An 8-bit unsigned integer whose values exist on the interval `[0, +255]`. - -## uint16 - -A 16-bit unsigned integer whose values exist on the interval `[0, +65,535]`. - -## uint32 - -A 32-bit unsigned integer whose values exist on the interval `[0, +4,294,967,295]`. - -## uint64 - -A 64-bit unsigned integer whose values exist on the interval `[0, +18,446,744,073,709,551,615]`. - -## float32 - -IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). - -## float64 - -IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). - -```{note} -IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. - -Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. -``` - -:::{admonition} Future extension -:class: hint -`complex64` and `complex128` data types are expected to be included in the next -version of this standard and to have the following casting rules (will be added -to {ref}`type-promotion`): - -![Type promotion diagram for complex data types in next version](/_static/images/dtype_promotion_complex.png) - -See [array-api/issues/102](https://github.com/data-apis/array-api/issues/102) -for more details. -::: - -```{note} -A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. -``` - -(data-type-objects)= -## Data Type Objects - -Data types ("dtypes") are objects which are used as `dtype` specifiers in functions and methods (e.g., `zeros((2, 3), dtype=float32)`). - -```{note} -A conforming implementation may add additional methods or attributes to data type objects beyond those described in this specification. -``` - -```{note} -Implementations may provide other ways to specify data types (e.g., `zeros((2, 3), dtype='f4')`) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. -``` - -A conforming implementation of the array API standard must provide and support data type objects having the following attributes and methods. - -### Methods - - - -(data-type-method-__eq__)= -### \_\_eq\_\_(self, other, /) - -Computes the truth value of `self == other` in order to test for data type object equality. - -#### Parameters - -- **self**: _<dtype>_ - - - data type instance. May be any supported data type. - -- **other**: _<dtype>_ - - - other data type instance. May be any supported data type. - -#### Returns - -- **out**: _<bool>_ - - - a boolean indicating whether the data type objects are equal. - -(data-type-defaults)= -## Default Data Types - -A conforming implementation of the array API standard must define the following default data types. - -- a default floating-point data type (either `float32` or `float64`). -- a default integer data type (either `int32` or `int64`). -- a default array index data type (either `int32` or `int64`). - -The default floating-point data type must be the same across platforms. - -The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. - -The default array index data type may be `int32` on 32-bit platforms, but the default should be `int64` otherwise. - -```{note} -The default data types should be clearly defined in a conforming library's documentation. -``` - -(data-type-categories)= -## Data Type Categories - -For the purpose of organizing functions within this specification, the following data type categories are defined. - -```{note} -Conforming libraries are not required to organize data types according to these categories. These -categories are only intended for use within this specification. -``` - -```{note} -Future versions of the specification will include additional categories for -complex data types. -``` - -### Numeric Data Types - -`int8`, `int16`, `int32`, `int64`, `uint8`, `uint16`, `uint32`, -`uint64`, `float32`, and `float64` (i.e., all data types except for `bool`). - -### Integer Data Types - -`int8`, `int16`, `int32`, `int64`, `uint8`, `uint16`, `uint32`, and -`uint64`. - -### Floating-point Data Types - -`float32` and `float64`. - -### Boolean Data Types - -`bool`. diff --git a/spec/API_specification/data_types.rst b/spec/API_specification/data_types.rst new file mode 100644 index 000000000..d645f9c58 --- /dev/null +++ b/spec/API_specification/data_types.rst @@ -0,0 +1,163 @@ +.. _data-types: + +Data Types +========== + + Array API specification for supported data types. + +A conforming implementation of the array API standard must provide and support the following data types. + +bool +---- + +Boolean (``True`` or ``False``). + +int8 +---- + +An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. + +int16 +----- + +A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. + +int32 +----- + +A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. + +int64 +----- + +A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. + +uint8 +----- + +An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. + +uint16 +------ + +A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. + +uint32 +------ + +A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. + +uint64 +------ + +A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. + +float32 +------- + +IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). + +float64 +------- + +IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). + +.. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. + +.. admonition:: Future extension + + ``complex64`` and ``complex128`` data types are expected to be included in the next version of this standard and to have the following casting rules (will be added to :ref:`type-promotion`): + + .. image:: /_static/images/dtype_promotion_complex.png + + See `array-api/issues/102 `_ for more details + +.. note:: + A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. + +.. _data-type-objects: + +Data Type Objects +----------------- + +Data types ("dtypes") are objects which are used as ``dtype`` specifiers in functions and methods (e.g., ``zeros((2, 3), dtype=float32)``). + +.. note:: + A conforming implementation may add additional methods or attributes to data type objects beyond those described in this specification. + +.. note:: + Implementations may provide other ways to specify data types (e.g., ``zeros((2, 3), dtype='f4')``) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. + +A conforming implementation of the array API standard must provide and support data type objects having the following attributes and methods. + +Methods +~~~~~~~ + +.. + NOTE: please keep the functions in alphabetical order + +.. currentmodule:: signatures.data_types + +.. autosummary:: + :toctree: generated + :template: method.rst + + __eq__ + + +.. _data-type-defaults: + +Default Data Types +------------------ + +A conforming implementation of the array API standard must define the following default data types. + +- a default floating-point data type (either ``float32`` or ``float64``). +- a default integer data type (either ``int32`` or ``int64``). +- a default array index data type (either ``int32`` or ``int64``). + +The default floating-point data type must be the same across platforms. + +The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. + +The default array index data type may be ``int32`` on 32-bit platforms, but the default should be ``int64`` otherwise. + +.. note:: + The default data types should be clearly defined in a conforming library's documentation. + +.. _data-type-categories: + +Data Type Categories +-------------------- + +For the purpose of organizing functions within this specification, the following data type categories are defined. + +.. note:: + Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. + +.. note:: + Future versions of the specification will include additional categories for complex data types. + + +Numeric Data Types +~~~~~~~~~~~~~~~~~~ + +``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64`` (i.e., all data types except for ``bool``). + +Integer Data Types +~~~~~~~~~~~~~~~~~~ + +``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. + +Floating-point Data Types +~~~~~~~~~~~~~~~~~~~~~~~~~ + +``float32`` and ``float64``. + +Boolean Data Types +~~~~~~~~~~~~~~~~~~ + +``bool``. diff --git a/spec/API_specification/signatures/data_types.py b/spec/API_specification/signatures/data_types.py new file mode 100644 index 000000000..b8a718613 --- /dev/null +++ b/spec/API_specification/signatures/data_types.py @@ -0,0 +1,20 @@ +from ._types import List, Tuple, Union, array, dtype + +def __eq__(self: dtype, other: dtype, /) -> bool: + """ + Computes the truth value of ``self == other`` in order to test for data type object equality. + + Parameters + ---------- + self: dtype + data type instance. May be any supported data type. + other: dtype + other data type instance. May be any supported data type. + + Returns + ------- + out: bool + a boolean indicating whether the data type objects are equal. + """ + +all = [__eq__] \ No newline at end of file From 07f991f491b29e6b612ea499840d1027b97275a3 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 22 Dec 2021 21:32:11 -0500 Subject: [PATCH 136/551] Transform function and method signatures to rst --- ....md => function_and_method_signatures.rst} | 61 +++++++++---------- 1 file changed, 29 insertions(+), 32 deletions(-) rename spec/API_specification/{function_and_method_signatures.md => function_and_method_signatures.rst} (52%) diff --git a/spec/API_specification/function_and_method_signatures.md b/spec/API_specification/function_and_method_signatures.rst similarity index 52% rename from spec/API_specification/function_and_method_signatures.md rename to spec/API_specification/function_and_method_signatures.rst index d199bcbb6..79115ed6e 100644 --- a/spec/API_specification/function_and_method_signatures.md +++ b/spec/API_specification/function_and_method_signatures.rst @@ -1,36 +1,34 @@ -(function-and-method-signatures)= +.. _function-and-method-signatures: -# Function and method signatures +Function and method signatures +============================== Function signatures in this standard adhere to the following: -1. Positional parameters must be - [positional-only](https://www.python.org/dev/peps/pep-0570/) parameters. +1. 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. - _Rationale: existing libraries have incompatible conventions, and using names - of positional parameters is not normal/recommended practice._ + *Rationale: existing libraries have incompatible conventions, and using names + of positional parameters is not normal/recommended practice.* - ```{note} +.. note:: Positional-only parameters are only available in Python >= 3.8. Libraries still supporting 3.7 or 3.6 may consider making the API standard-compliant namespace >= 3.8. Alternatively, they can add guidance to their users in the - documentation to use the functions as if they were positional-only. - ``` + documentation to use the functions as if they were positional-only. -2. Optional parameters must be - [keyword-only](https://www.python.org/dev/peps/pep-3102/) arguments. +2. Optional parameters must be `keyword-only `_ arguments. - _Rationale: this leads to more readable code, and it makes it easier to + *Rationale: this leads to more readable code, and it makes it easier to evolve an API over time by adding keywords without having to worry about - keyword order._ + keyword order.* 3. For functions that have a single positional array parameter, that parameter - is called `x`. For functions that have multiple array parameters, those - parameters are called `xi` with `i = 1, 2, ...` (i.e., `x1`, `x2`). + is called ``x``. For functions that have multiple array parameters, those + parameters are called ``xi`` with ``i = 1, 2, ...`` (i.e., ``x1``, ``x2``). 4. Type annotations are left out of the signatures themselves for readability; however, they are added to individual parameter descriptions. For code which aims to @@ -38,25 +36,24 @@ Function signatures in this standard adhere to the following: A function signature and description will look like: -``` -funcname(x1, x2, /, *, key1=-1, key2=None) +:: - Parameters + funcname(x1, x2, /, *, key1=-1, key2=None) -> out: + Parameters - x1 : array - description - x2 : array - description - key1 : int - description - key2 : Optional[str] - description + x1 : array + description + x2 : array + description + key1 : int + description + key2 : Optional[str] + description - Returns + Returns - out : array - description -``` + out : array + description -Method signatures will follow the same conventions modulo the addition of -`self`. + +Method signatures will follow the same conventions modulo the addition of ``self``. From ed1f7a8b48986cb4924fb600389784ea67821294 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 22 Dec 2021 22:10:57 -0500 Subject: [PATCH 137/551] Transform indexing.md to rst --- spec/API_specification/indexing.md | 208 ---------------------------- spec/API_specification/indexing.rst | 195 ++++++++++++++++++++++++++ 2 files changed, 195 insertions(+), 208 deletions(-) delete mode 100644 spec/API_specification/indexing.md create mode 100644 spec/API_specification/indexing.rst diff --git a/spec/API_specification/indexing.md b/spec/API_specification/indexing.md deleted file mode 100644 index f06cae9d3..000000000 --- a/spec/API_specification/indexing.md +++ /dev/null @@ -1,208 +0,0 @@ -(indexing)= - -# Indexing - -> Array API specification for indexing arrays. - -A conforming implementation of the array API standard must adhere to the following conventions. - -## Single-axis Indexing - -To index a single array axis, an array must support standard Python indexing rules. Let `n` be the axis (dimension) size. - -- An integer index must be an object satisfying [`operator.index`](https://www.python.org/dev/peps/pep-0357/) (e.g., `int`). - -- Nonnegative indices must start at `0` (i.e., zero-based indexing). - -- **Valid** nonnegative indices must reside on the half-open interval `[0, n)`. - - ```{note} - This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. - ``` - -- Negative indices must count backward from the last array index, starting from `-1` (i.e., negative-one-based indexing, where `-1` refers to the last array index). - - ```{note} - A negative index `j` is equivalent to `n-j`; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. - ``` - -- **Valid** negative indices must reside on the closed interval `[-n, -1]`. - - ```{note} - This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. - ``` - -- A negative index `j` is related to a zero-based nonnegative index `i` via `i = n+j`. - -- Colons `:` must be used for [slices](https://docs.python.org/3/library/functions.html#slice): `start:stop:step`, where `start` is inclusive and `stop` is exclusive. - -```{note} -The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. -``` - -### Slice Syntax - -The basic slice syntax is `i:j:k` where `i` is the starting index, `j` is the stopping index, and `k` is the step (`k != 0`). A slice may contain either one or two colons, with either an integer value or nothing on either side of each colon. The following are valid slices. - -```text -A[:] -A[i:] -A[:j] -A[i:k] -A[::] -A[i::] -A[:j:] -A[::k] -A[i:j:] -A[i::k] -A[:j:k] -A[i::k] -A[i:j:k] -``` - -```{note} -Slice syntax can be equivalently achieved using the Python built-in [`slice()`](https://docs.python.org/3/library/functions.html#slice) API. From the perspective of `A`, the behavior of `A[i:j:k]` and `A[slice(i, j, k)]` is indistinguishable (i.e., both retrieve the same set of items from `__getitem__`). -``` - -Using a slice to index a single array axis must select `m` elements with index values - -```text -i, i+k, i+2k, i+3k, ..., i+(m-1)k -``` - -where - -```text -m = q + r -``` - -and `q` and `r` (`r != 0`) are the quotient and remainder obtained by dividing `j-i` by `k` - -```text -j - i = qk + r -``` - -such that - -```text -j > i + (m-1)k -``` - -```{note} -For `i` on the interval `[0, n)` (where `n` is the axis size), `j` on the interval `(0, n]`, `i` less than `j`, and positive step `k`, a starting index `i` is **always** included, while the stopping index `j` is **always** excluded. This preserves `x[:i]+x[i:]` always being equal to `x`. -``` - -```{note} -Using a slice to index into a single array axis should select the same elements as using a slice to index a Python list of the same size. -``` - -Slice syntax must have the following defaults. Let `n` be the axis (dimension) size. - -- If `k` is not provided (e.g., `0:10`), `k` must equal `1`. -- If `k` is greater than `0` and `i` is not provided (e.g., `:10:2`), `i` must equal `0`. -- If `k` is greater than `0` and `j` is not provided (e.g., `0::2`), `j` must equal `n`. -- If `k` is less than `0` and `i` is not provided (e.g., `:10:-2`), `i` must equal `n-1`. -- If `k` is less than `0` and `j` is not provided (e.g., `0::-2`), `j` must equal `-n-1`. - -Using a slice to index a single array axis must adhere to the following rules. Let `n` be the axis (dimension) size. - -- If `i` equals `j`, a slice must return an empty array, whose axis (dimension) size along the indexed axis is `0`. - -- Indexing via `:` and `::` must be equivalent and have defaults derived from the rules above. Both `:` and `::` indicate to select all elements along a single axis (dimension). - -```{note} -This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where `0:100` and `0:10` are equivalent on a list of length `10`. -``` - -The following ranges for the start and stop values of a slice must be supported. Let `n` be the axis (dimension) size being sliced. For a slice `i:j:k`, the behavior specified above should be implemented for the following: - -- `i` or `j` omitted (`None`). -- `-n <= i <= n`. -- For `k > 0` or `k` omitted (`None`), `-n <= j <= n`. -- For `k < 0`, `-n - 1 <= j <= max(0, n - 1)`. - -The behavior outside of these bounds is unspecified. - -```{note} -_Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip (consistent with Python `list` slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ -``` - -## Multi-axis Indexing - -Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let `N` be the number of dimensions ("rank") of a multi-dimensional array `A`. - -- Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., `A[:, 2:10, :, 5]`). - - ```{note} - In Python, `A[(exp1, exp2, ..., expN)]` is equivalent to `A[exp1, exp2, ..., expN]`; the latter is syntactic sugar for the former. - - Accordingly, if `A` has rank `1`, then `A[(2:10,)]` must be equivalent to `A[2:10]`. If `A` has rank `2`, then `A[(2:10, :)]` must be equivalent to `A[2:10, :]`. And so on and so forth. - ``` - -- Providing a single nonnegative integer `i` as a single-axis index must index the same elements as the slice `i:i+1`. - -- Providing a single negative integer `i` as a single-axis index must index the same elements as the slice `n+i:n+i+1`, where `n` is the axis (dimension) size. - -- Providing a single integer as a single-axis index must reduce the number of array dimensions by `1` (i.e., the array rank should decrease by one; if `A` has rank `2`, `rank(A)-1 == rank(A[0, :])`). In particular, a selection tuple with the `m`th element an integer (and all other entries `:`) indexes a sub-array with rank `N-1`. - - ```{note} - When providing a single integer as a single-axis index to an array of rank `1`, the result should be an array of rank `0`, not a NumPy scalar. Note that this behavior differs from NumPy. - ``` - -- Providing a slice must retain array dimensions (i.e., the array rank must remain the same; `rank(A) == rank(A[:])`). - -- Providing [ellipsis](https://docs.python.org/3/library/constants.html#Ellipsis) must apply `:` to each dimension necessary to index all dimensions (e.g., if `A` has rank `4`, `A[1:, ..., 2:5] == A[1:, :, :, 2:5]`). Only a single ellipsis must be allowed. An `IndexError` exception must be raised if more than one ellipsis is provided. - -- Providing an empty tuple or an ellipsis to an array of rank `0` must result in an array of the same rank (i.e., if `A` has rank `0`, `A == A[()]` and `A == A[...]`). - - ```{note} - This behavior differs from NumPy where providing an empty tuple to an array of rank `0` returns a NumPy scalar. - ``` - -- Except in the case of providing a single ellipsis (e.g., `A[2:10, ...]` or `A[1:, ..., 2:5]`), the number of provided single-axis indexing expressions should equal `N`. For example, if `A` has rank `2`, a single-axis indexing expression should be explicitly provided for both axes (e.g., `A[2:10, :]`). An `IndexError` exception should be raised if the number of provided single-axis indexing expressions is less than `N`. - - ```{note} - Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. - - To perform flat indexing, use `reshape(x, (-1,))[integer]`. - ``` - -- An `IndexError` exception must be raised if the number of provided single-axis indexing expressions is greater than `N`. - -```{note} -This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. - -_Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to `0`, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations._ -``` - -## Boolean Array Indexing - -:::{admonition} Data-dependent output shape -:class: important - -For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See {ref}`data-dependent-output-shapes` section for more details. -::: - -An array must support indexing where the **sole index** is an `M`-dimensional boolean array `B` with shape `S1 = (s1, ..., sM)` according to the following rules. Let `A` be an `N`-dimensional array with shape `S2 = (s1, ..., sM, ..., sN)`. - -- If `N >= M`, then `A[B]` must replace the first `M` dimensions of `A` with a single dimension having a size equal to the number of `True` elements in `B`. The values in the resulting array must be in row-major (C-style order); this is equivalent to `A[nonzero(B)]`. - - ```{note} - For example, if `N == M == 2`, indexing `A` via a boolean array `B` will return a one-dimensional array whose size is equal to the number of `True` elements in `B`. - ``` - -- If `N < M`, then an `IndexError` exception must be raised. - -- The size of each dimension in `B` must equal the size of the corresponding dimension in `A` or be `0`, beginning with the first dimension in `A`. If a dimension size does not equal the size of the corresponding dimension in `A` and is not `0`, then an `IndexError` exception must be raised. - -- The elements of a boolean index array must be iterated in row-major, C-style order, with the exception of zero-dimensional boolean arrays. - -- A zero-dimensional boolean index array (equivalent to `True` or `False`) must follow the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length `1` if the index array's value is `True` and of length `0` if the index array's value is `False`. Accordingly, for a zero-dimensional boolean index array `B`, the result of `A[B]` has shape `S = (1, s1, ..., sN)` if the index array's value is `True` and has shape `S = (0, s1, ..., sN)` if the index array's value is `False`. - -## Return Values - -The result of an indexing operation (e.g., multi-axis indexing, boolean array indexing, etc) must be an array of the same data type as the indexed array. - -```{note} -The specified return value behavior includes indexing operations which return a single value (e.g., accessing a single element within a one-dimensional array). -``` diff --git a/spec/API_specification/indexing.rst b/spec/API_specification/indexing.rst new file mode 100644 index 000000000..55523c007 --- /dev/null +++ b/spec/API_specification/indexing.rst @@ -0,0 +1,195 @@ +.. _indexing: + +Indexing +======== + + Array API specification for indexing arrays. + +A conforming implementation of the array API standard must adhere to the following conventions. + +Single-axis Indexing +-------------------- + +To index a single array axis, an array must support standard Python indexing rules. Let ``n`` be the axis (dimension) size. + +- An integer index must be an object satisfying `operator.index `_ (e.g., ``int``). + +- Nonnegative indices must start at ``0`` (i.e., zero-based indexing). + +- **Valid** nonnegative indices must reside on the half-open interval ``[0, n)``. + +.. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- Negative indices must count backward from the last array index, starting from ``-1`` (i.e., negative-one-based indexing, where ``-1`` refers to the last array index). + +.. note:: + A negative index ``j`` is equivalent to ``n-j``; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. + +- **Valid** negative indices must reside on the closed interval ``[-n, -1]``. + +.. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- A negative index ``j`` is related to a zero-based nonnegative index ``i`` via ``i = n+j``. + +- Colons ``:`` must be used for `slices `_: ``start:stop:step``, where ``start`` is inclusive and ``stop`` is exclusive. + +.. note:: + The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. + +Slice Syntax +~~~~~~~~~~~~ + +The basic slice syntax is ``i:j:k`` where ``i`` is the starting index, ``j`` is the stopping index, and ``k`` is the step (``k != 0``). A slice may contain either one or two colons, with either an integer value or nothing on either side of each colon. The following are valid slices. + +:: + + A[:] + A[i:] + A[:j] + A[i:k] + A[::] + A[i::] + A[:j:] + A[::k] + A[i:j:] + A[i::k] + A[:j:k] + A[i::k] + A[i:j:k] + +.. note:: + Slice syntax can be equivalently achieved using the Python built-in `slice() `_ API. From the perspective of ``A``, the behavior of ``A[i:j:k]`` and ``A[slice(i, j, k)]`` is indistinguishable (i.e., both retrieve the same set of items from ``__getitem__``). + +Using a slice to index a single array axis must select ``m`` elements with index values + +:: + + i, i+k, i+2k, i+3k, ..., i+(m-1)k + +where + +:: + + m = q + r + +and ``q`` and ``r`` (``r != 0``) are the quotient and remainder obtained by dividing ``j-i`` by ``k`` + +:: + + j - i = qk + r + +such that + +:: + + j > i + (m-1)k + +.. note:: + For ``i`` on the interval ``[0, n)`` (where ``n`` is the axis size), ``j`` on the interval ``(0, n]``, ``i`` less than ``j``, and positive step ``k``, a starting index ``i`` is **always** included, while the stopping index ``j`` is **always** excluded. This preserves ``x[:i]+x[i:]`` always being equal to ``x``. + +.. note:: + Using a slice to index into a single array axis should select the same elements as using a slice to index a Python list of the same size. + +Slice syntax must have the following defaults. Let ``n`` be the axis (dimension) size. + +- If ``k`` is not provided (e.g., ``0:10``), ``k`` must equal ``1``. +- If ``k`` is greater than ``0`` and ``i`` is not provided (e.g., ``:10:2``), ``i`` must equal ``0``. +- If ``k`` is greater than ``0`` and ``j`` is not provided (e.g., ``0::2``), ``j`` must equal ``n``. +- If ``k`` is less than ``0`` and ``i`` is not provided (e.g., ``:10:-2``), ``i`` must equal ``n-1``. +- If ``k`` is less than ``0`` and ``j`` is not provided (e.g., ``0::-2``), ``j`` must equal ``-n-1``. + +Using a slice to index a single array axis must adhere to the following rules. Let ``n`` be the axis (dimension) size. + +- If ``i`` equals ``j``, a slice must return an empty array, whose axis (dimension) size along the indexed axis is ``0``. + +- Indexing via ``:`` and ``::`` must be equivalent and have defaults derived from the rules above. Both ``:`` and ``::`` indicate to select all elements along a single axis (dimension). + +.. note:: + This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where ``0:100`` and ``0:10`` are equivalent on a list of length ``10``. + +The following ranges for the start and stop values of a slice must be supported. Let ``n`` be the axis (dimension) size being sliced. For a slice ``i:j:k``, the behavior specified above should be implemented for the following: + +- ``i`` or ``j`` omitted (``None``). +- ``-n <= i <= n``. +- For ``k > 0`` or ``k`` omitted (``None``), ``-n <= j <= n``. +- For ``k < 0``, ``-n - 1 <= j <= max(0, n - 1)``. + +The behavior outside of these bounds is unspecified. + +.. note:: + *Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip (consistent with Python* ``list`` *slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +Multi-axis Indexing +------------------- + +Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let ``N`` be the number of dimensions ("rank") of a multi-dimensional array ``A``. + +- Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., ``A[:, 2:10, :, 5]``). + +.. note:: + In Python, ``A[(exp1, exp2, ..., expN)]`` is equivalent to ``A[exp1, exp2, ..., expN]``; the latter is syntactic sugar for the former. + + Accordingly, if ``A`` has rank ``1``, then ``A[(2:10,)]`` must be equivalent to ``A[2:10]``. If ``A`` has rank ``2``, then ``A[(2:10, :)]`` must be equivalent to ``A[2:10, :]``. And so on and so forth. + +- Providing a single nonnegative integer ``i`` as a single-axis index must index the same elements as the slice ``i:i+1``. + +- Providing a single negative integer ``i`` as a single-axis index must index the same elements as the slice ``n+i:n+i+1``, where ``n`` is the axis (dimension) size. + +- Providing a single integer as a single-axis index must reduce the number of array dimensions by ``1`` (i.e., the array rank should decrease by one; if ``A`` has rank ``2``, ``rank(A)-1 == rank(A[0, :])``). In particular, a selection tuple with the ``m``th element an integer (and all other entries ``:``) indexes a sub-array with rank ``N-1``. + +.. note:: + When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. + +- Providing a slice must retain array dimensions (i.e., the array rank must remain the same; ``rank(A) == rank(A[:])``). + +- Providing `ellipsis `_ must apply ``:`` to each dimension necessary to index all dimensions (e.g., if ``A`` has rank ``4``, ``A[1:, ..., 2:5] == A[1:, :, :, 2:5]``). Only a single ellipsis must be allowed. An ``IndexError`` exception must be raised if more than one ellipsis is provided. + +- Providing an empty tuple or an ellipsis to an array of rank ``0`` must result in an array of the same rank (i.e., if ``A`` has rank ``0``, ``A == A[()]`` and ``A == A[...]``). + +.. note:: + This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. + +- Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions is less than ``N``. + +.. note:: + Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. + + To perform flat indexing, use ``reshape(x, (-1,))[integer]``. + +- An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions is greater than ``N``. + +.. note:: + This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. + + *Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to* ``0`` *, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +Boolean Array Indexing +---------------------- + +.. important:: Data-dependent output shape + For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See :ref:`data-dependent-output-shapes` section for more details. + +An array must support indexing where the **sole index** is an ``M``-dimensional boolean array ``B`` with shape ``S1 = (s1, ..., sM)`` according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S2 = (s1, ..., sM, ..., sN)``. + +- If ``N >= M``, then ``A[B]`` must replace the first ``M`` dimensions of ``A`` with a single dimension having a size equal to the number of ``True`` elements in ``B``. The values in the resulting array must be in row-major (C-style order); this is equivalent to ``A[nonzero(B)]``. + +.. note:: + For example, if ``N == M == 2``, indexing ``A`` via a boolean array ``B`` will return a one-dimensional array whose size is equal to the number of ``True`` elements in ``B``. + +- If ``N < M``, then an ``IndexError`` exception must be raised. + +- The size of each dimension in ``B`` must equal the size of the corresponding dimension in ``A`` or be ``0``, beginning with the first dimension in ``A``. If a dimension size does not equal the size of the corresponding dimension in ``A`` and is not ``0``, then an ``IndexError`` exception must be raised. + +- The elements of a boolean index array must be iterated in row-major, C-style order, with the exception of zero-dimensional boolean arrays. + +- A zero-dimensional boolean index array (equivalent to ``True`` or ``False``) must follow the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length ``1`` if the index array's value is ``True`` and of length ``0`` if the index array's value is ``False``. Accordingly, for a zero-dimensional boolean index array ``B``, the result of ``A[B]`` has shape ``S = (1, s1, ..., sN)`` if the index array's value is ``True`` and has shape ``S = (0, s1, ..., sN)`` if the index array's value is ``False``. + +Return Values +------------- + +The result of an indexing operation (e.g., multi-axis indexing, boolean array indexing, etc) must be an array of the same data type as the indexed array. + +.. note:: + The specified return value behavior includes indexing operations which return a single value (e.g., accessing a single element within a one-dimensional array). From d60fea385c80946a727e4bdd8c1ad61fb6dc61a2 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Jan 2022 01:40:56 -0800 Subject: [PATCH 138/551] Fix signature for `linalg.vecdot` (#358) --- spec/extensions/linear_algebra_functions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 2e054f8aa..6bdcdbd78 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -573,7 +573,7 @@ Returns the sum along the specified diagonals of a matrix (or a stack of matrice The returned array must have the same data type as `x`. (function-linalg-vecdot)= -### linalg.vecdot(x1, x2, /, *, axis=None) +### linalg.vecdot(x1, x2, /, *, axis=-1) Alias for {ref}`function-vecdot`. From 85b549947e41d3a4b65fa3b17f1a95515a35e11c Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 5 Jan 2022 11:04:07 +0100 Subject: [PATCH 139/551] Change the type annotation for `__array_namespace__` to Any (#357) See https://github.com/data-apis/array-api/issues/267#issuecomment-994868224 --- spec/API_specification/array_object.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index e950643b4..7eeddd4eb 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -473,7 +473,7 @@ Returns an object that has all the array API functions on it. #### Returns -- **out**: _<object>_ +- **out**: _<Any>_ - an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. From c1e942b9fe9f4d4937b85077da5e391906841b60 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 10 Jan 2022 11:05:20 -0500 Subject: [PATCH 140/551] Add review changes --- .../signatures/array_object.py | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 0562a90b3..53d87333b 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -6,7 +6,8 @@ def __init__(self) -> None: Initialize the attributes for the array object class. """ - self.dtype = None + @property + def dtype() -> dtype: """ Data type of the array elements. @@ -16,7 +17,8 @@ def __init__(self) -> None: array data type. """ - self.device = None + @property + def device() -> device: """ Hardware device the array data resides on. @@ -26,7 +28,8 @@ def __init__(self) -> None: a ``device`` object (see :ref:`device-support`). """ - self.mT = None + @property + def mT() -> array: """ Transpose of a matrix (or a stack of matrices). @@ -38,7 +41,8 @@ def __init__(self) -> None: array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape ``(..., M, N)``, the returned array must have shape ``(..., N, M)``). The returned array must have the same data type as the original array. """ - self.ndim = None + @property + def ndim() -> int: """ Number of array dimensions (axes). @@ -48,7 +52,8 @@ def __init__(self) -> None: number of array dimensions (axes). """ - self.shape = None + @property + def shape() -> Tuple[Optional[int], ...]: """ Array dimensions. @@ -64,7 +69,8 @@ def __init__(self) -> None: - The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. """ - self.size = None + @property + def size() -> Optional[int]: """ Number of elements in an array. @@ -80,7 +86,8 @@ def __init__(self) -> None: - For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. """ - self.T = None + @property + def T() -> array: """ Transpose of the array. @@ -939,4 +946,4 @@ def to_device(self: array, device: device, /, *, stream: Optional[Union[int, Any Notes ----- - If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. - """ \ No newline at end of file + """ From 94bd0cb306f59e69189b09241b3db2350392d598 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 10 Jan 2022 11:38:15 -0500 Subject: [PATCH 141/551] Fix block quotes --- spec/API_specification/broadcasting.rst | 65 ++++++++++++------------- 1 file changed, 31 insertions(+), 34 deletions(-) diff --git a/spec/API_specification/broadcasting.rst b/spec/API_specification/broadcasting.rst index b930aaa12..db14a41fe 100644 --- a/spec/API_specification/broadcasting.rst +++ b/spec/API_specification/broadcasting.rst @@ -71,48 +71,45 @@ Examples The following examples demonstrate the application of the broadcasting algorithm for two compatible arrays. :: - A (4d array): 8 x 1 x 6 x 1 - B (3d array): 7 x 1 x 5 - --------------------------------- - Result (4d array): 8 x 7 x 6 x 5 - A (2d array): 5 x 4 - B (1d array): 1 - ------------------------- - Result (2d array): 5 x 4 - - A (2d array): 5 x 4 - B (1d array): 4 - ------------------------- - Result (2d array): 5 x 4 - - A (3d array): 15 x 3 x 5 - B (3d array): 15 x 1 x 5 - ------------------------------ - Result (3d array): 15 x 3 x 5 - - A (3d array): 15 x 3 x 5 - B (2d array): 3 x 5 - ------------------------------ - Result (3d array): 15 x 3 x 5 - - A (3d array): 15 x 3 x 5 - B (2d array): 3 x 1 - ------------------------------ - Result (3d array): 15 x 3 x 5 + A (4d array): 8 x 1 x 6 x 1 + B (3d array): 7 x 1 x 5 + --------------------------------- + Result (4d array): 8 x 7 x 6 x 5 + A (2d array): 5 x 4 + B (1d array): 1 + ------------------------- + Result (2d array): 5 x 4 + A (2d array): 5 x 4 + B (1d array): 4 + ------------------------- + Result (2d array): 5 x 4 + A (3d array): 15 x 3 x 5 + B (3d array): 15 x 1 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 1 + ------------------------------ + Result (3d array): 15 x 3 x 5 The following examples demonstrate array shapes which do **not** broadcast. :: - A (1d array): 3 - B (1d array): 4 # dimension does not match - A (2d array): 2 x 1 - B (3d array): 8 x 4 x 3 # second dimension does not match + A (1d array): 3 + B (1d array): 4 # dimension does not match + + A (2d array): 2 x 1 + B (3d array): 8 x 4 x 3 # second dimension does not match - A (3d array): 15 x 3 x 5 - B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended + A (3d array): 15 x 3 x 5 + B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended In-place Semantics ------------------ From 69f453cd3ba51b817072225206f58421e5085631 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 10 Jan 2022 12:37:31 -0500 Subject: [PATCH 142/551] Add the constants as floats --- spec/API_specification/signatures/constants.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/signatures/constants.py b/spec/API_specification/signatures/constants.py index 069f10005..813b6d079 100644 --- a/spec/API_specification/signatures/constants.py +++ b/spec/API_specification/signatures/constants.py @@ -1,21 +1,21 @@ -e = None +e = 2.718281828459045 """ IEEE 754 floating-point representation of Euler's constant. ``e = 2.71828182845904523536028747135266249775724709369995...`` """ -inf = None +inf = float('inf') """ IEEE 754 floating-point representation of (positive) infinity. """ -nan = None +nan = float('nan') """ IEEE 754 floating-point representation of Not a Number (``NaN``). """ -pi = None +pi = 3.141592653589793 """ IEEE 754 floating-point representation of the mathematical constant ``π``. From 202f2b45e6094f8c355aabc0892050295186bec1 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 10 Jan 2022 14:37:53 -0500 Subject: [PATCH 143/551] Add review changes --- spec/API_specification/signatures/_types.py | 14 ++++++++++---- .../signatures/creation_functions.py | 19 +++++++++---------- spec/conf.py | 1 + 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/spec/API_specification/signatures/_types.py b/spec/API_specification/signatures/_types.py index 99001e470..f4d0548bf 100644 --- a/spec/API_specification/signatures/_types.py +++ b/spec/API_specification/signatures/_types.py @@ -4,9 +4,10 @@ The type variables should be replaced with the actual types for a given library, e.g., for NumPy TypeVar('array') would be replaced with ndarray. """ +from __future__ import annotations from dataclasses import dataclass -from typing import Any, List, Literal, Optional, Sequence, Tuple, TypeVar, Union +from typing import Any, List, Literal, Optional, Sequence, Tuple, TypeVar, Union, Protocol array = TypeVar('array') device = TypeVar('device') @@ -32,9 +33,14 @@ class iinfo_object: max: int min: int -# This should really be recursive, but that isn't supported yet. -NestedSequence = Sequence[Any] + +_T_co = TypeVar("_T_co", covariant=True) + +class NestedSequence(Protocol[_T_co]): + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: ... + def __len__(self, /) -> int: ... + __all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', 'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', -'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object'] \ No newline at end of file +'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object'] diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index 928c58ade..7ab6da3c4 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -44,15 +44,10 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then - if all values are of type ``bool``, the output data type must be ``bool``. - - if the values are a mixture of ``bool``s and ``int``, the output data type must be the default integer data type. - - if one or more values are ``float``s, the output data type must be the default floating-point data type. + - if the values are a mixture of ``bool``\s and ``int``, the output data type must be the default integer data type. + - if one or more values are ``float``\s, the output data type must be the default floating-point data type. Default: ``None``. - - **Note** - - If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. - To perform an explicit cast, use :ref:`function-astype`. device: Optional[device] device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. copy: Optional[bool] @@ -62,6 +57,10 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr ------- out: array an array containing the data from ``obj``. + + Notes + ----- + - If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :ref:`function-astype`. """ def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: @@ -104,7 +103,7 @@ def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: """ - Returns a two-dimensional array with ones on the ``k``th diagonal and zeros elsewhere. + Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. Parameters ---------- @@ -122,7 +121,7 @@ def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Opti Returns ------- out: array - an array where all elements are equal to zero, except for the ``k``th diagonal, whose values are equal to one. + an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. """ def from_dlpack(x: object, /) -> array: @@ -334,7 +333,7 @@ def triu(x: array, /, *, k: int = 0) -> array: def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: """ - Returns a new array having a specified `shape` and filled with zeros. + Returns a new array having a specified ``shape`` and filled with zeros. Parameters ---------- diff --git a/spec/conf.py b/spec/conf.py index 5370da268..3d54a4d3e 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -46,6 +46,7 @@ autodoc_typehints = 'signature' add_module_names = False napoleon_custom_sections = [('Returns', 'params_style')] +default_role = 'code' # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] From 5b2075421f4707b9ffa2c03b4f57d8017a258aec Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 10 Jan 2022 14:39:48 -0500 Subject: [PATCH 144/551] Remove unused imports --- spec/API_specification/signatures/data_types.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/signatures/data_types.py b/spec/API_specification/signatures/data_types.py index b8a718613..fd00521f1 100644 --- a/spec/API_specification/signatures/data_types.py +++ b/spec/API_specification/signatures/data_types.py @@ -1,4 +1,4 @@ -from ._types import List, Tuple, Union, array, dtype +from ._types import dtype def __eq__(self: dtype, other: dtype, /) -> bool: """ @@ -17,4 +17,4 @@ def __eq__(self: dtype, other: dtype, /) -> bool: a boolean indicating whether the data type objects are equal. """ -all = [__eq__] \ No newline at end of file +all = [__eq__] From 0e423b041073c0be2f291ff1d1348a2ea038a2c9 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 10 Jan 2022 20:29:17 -0700 Subject: [PATCH 145/551] Sort the entries in the API specification table of contents (#365) This makes the sidebar easier to navigate. --- spec/API_specification/index.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index 55faa1c4d..1d4c9cfef 100644 --- a/spec/API_specification/index.rst +++ b/spec/API_specification/index.rst @@ -7,20 +7,20 @@ API specification :caption: API specification :maxdepth: 3 - function_and_method_signatures array_object - indexing - data_types - data_type_functions - type_promotion broadcasting + constants creation_functions - manipulation_functions + data_type_functions + data_types elementwise_functions - statistical_functions + function_and_method_signatures + indexing linear_algebra_functions + manipulation_functions searching_functions - sorting_functions set_functions + sorting_functions + statistical_functions + type_promotion utility_functions - constants From dec7fef38fe1fda978f52476bdaa48122b771feb Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 10 Jan 2022 20:30:12 -0700 Subject: [PATCH 146/551] Prevent autosummary from using non-Python signature syntax in its tables (#364) As suggested here https://github.com/data-apis/array-api/pull/348#issuecomment-1004380206. --- spec/conf.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/spec/conf.py b/spec/conf.py index 5370da268..5493713b3 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -47,6 +47,16 @@ add_module_names = False napoleon_custom_sections = [('Returns', 'params_style')] +# Make autosummary show the signatures of functions in the tables using actual +# Python syntax. There's currently no supported way to do this, so we have to +# just patch out the function that processes the signatures. See +# https://github.com/sphinx-doc/sphinx/issues/10053. +import sphinx.ext.autosummary as autosummary_mod +if hasattr(autosummary_mod, '_module'): + # It's a sphinx deprecated module wrapper object + autosummary_mod = autosummary_mod._module +autosummary_mod.mangle_signature = lambda sig, max_chars=30: sig + # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -162,4 +172,4 @@ def process_signature(app, what, name, obj, options, signature, return_annotatio return signature, return_annotation def setup(app): - app.connect("autodoc-process-signature", process_signature) \ No newline at end of file + app.connect("autodoc-process-signature", process_signature) From cef078e66f4a445b49c02c2748a7444107c05402 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 12 Jan 2022 17:47:06 -0500 Subject: [PATCH 147/551] Fix notes and device type override --- .../signatures/array_object.py | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 62fbb8feb..9484650b5 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -1,4 +1,5 @@ -from ._types import array, dtype, device, Optional, Tuple, Union, Any, PyCapsule, Enum, ellipsis +from ._types import array, dtype, Optional, Tuple, Union, Any, PyCapsule, Enum, ellipsis +from ._types import device as Device class array(): def __init__(self) -> None: @@ -18,7 +19,7 @@ def dtype() -> dtype: """ @property - def device() -> device: + def device() -> Device: """ Hardware device the array data resides on. @@ -244,13 +245,25 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for `stream` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. - **Note** + **Tip** - Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronization than necessary. - Device-specific notes: + Returns + ------- + capsule: PyCapsule + a DLPack capsule for the array. See :ref:`data-interchange` for details. + + Notes + ----- + - Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + - Device-specific notes: - **CUDA** + **CUDA** - ``None``: producer must assume the legacy default stream (default). - ``1``: the legacy default stream. @@ -259,26 +272,13 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. - **ROCm** + **ROCm** - ``None``: producer must assume the legacy default stream (default). - ``0``: the default stream. - ``> 2``: stream number represented as a Python integer. Using ``1`` and ``2`` is not supported. - - **Tip** - - It is recommended that implementers explicitly handle streams. If - they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` - (ROCm) is preferred. ``None`` is a safe default for developers who do - not want to think about stream handling at all, potentially at the - cost of more synchronization than necessary. - - Returns - ------- - capsule: PyCapsule - a DLPack capsule for the array. See :ref:`data-interchange` for details. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -925,7 +925,7 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_xor`. """ - def to_device(self: array, device: device, /, *, stream: Optional[Union[int, Any]] = None) -> array: + def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: """ Copy the array from the device on which it currently resides to the specified ``device``. From 35671a4d7389bf0601a67741cf498245c49b0127 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Mon, 17 Jan 2022 09:24:26 +0000 Subject: [PATCH 148/551] Clarify that the results of division operations on integer array data types resulting in floating-point outputs is implementation-defined (#362) * Make int inputs for divide functions out-of-scope * Clarify mixed kind promotion is unspecified for divide notes * Clearer language for noting mixed kind promotion * Prohibit div functions return int arrays Also fixes related note wording for `min()` and `max()` * Better legibility of mixed kinds note Co-authored-by: Athan Co-authored-by: Athan --- spec/API_specification/array_object.md | 8 +++++++- spec/API_specification/elementwise_functions.md | 8 +++++++- spec/API_specification/statistical_functions.md | 4 ++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md index 7eeddd4eb..46ba3648e 100644 --- a/spec/API_specification/array_object.md +++ b/spec/API_specification/array_object.md @@ -1115,7 +1115,7 @@ Calculates an implementation-dependent approximation of exponentiation by raisin ```{note} If both `self` and `other` have integer data types, the result of `__pow__` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. -If `self` has an integer data type and `other` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). +If `self` has an integer data type and `other` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. ``` #### Special Cases @@ -1249,6 +1249,12 @@ Element-wise results must equal the results returned by the equivalent element-w Evaluates `self_i / other_i` for each element of an array instance with the respective element of the array `other`. +```{note} +If one or both of `self` and `other` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + +Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. +``` + #### Special Cases For floating-point operands, let `self` equal `x1` and `other` equal `x2`. diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md index f7adb7373..9602f5f7c 100644 --- a/spec/API_specification/elementwise_functions.md +++ b/spec/API_specification/elementwise_functions.md @@ -528,6 +528,12 @@ For floating-point operands, Calculates the division for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. +```{note} +If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + +Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. +``` + #### Special Cases For floating-point operands, @@ -1223,7 +1229,7 @@ Calculates an implementation-dependent approximation of exponentiation by raisin ```{note} If both `x1` and `x2` have integer data types, the result of `pow` when `x2_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. -If `x1` has an integer data type and `x2` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). +If `x1` has an integer data type and `x2` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. ``` #### Special Cases diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md index fb0ca7c21..052cbcbbd 100644 --- a/spec/API_specification/statistical_functions.md +++ b/spec/API_specification/statistical_functions.md @@ -21,7 +21,7 @@ A conforming implementation of the array API standard must provide and support t Calculates the maximum value of the input array `x`. ```{note} -When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the minimum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `-infinity`). +When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the minimum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `-infinity`). ``` #### Special Cases @@ -92,7 +92,7 @@ Let `N` equal the number of elements over which to compute the arithmetic mean. Calculates the minimum value of the input array `x`. ```{note} -When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the maximum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `+infinity`). +When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the maximum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `+infinity`). ``` #### Special Cases From e059ae24b4f1674ba36ffb3d3fa5097273b33858 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 17 Jan 2022 02:25:41 -0700 Subject: [PATCH 149/551] Add the autosummary generated files to .gitignore and 'make clean' (#363) --- .gitignore | 3 ++- spec/Makefile | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index dfedda47f..0ca7c019e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ build/ .vscode/ node_modules/ __pycache__/ -*.pyc \ No newline at end of file +*.pyc +spec/**/generated diff --git a/spec/Makefile b/spec/Makefile index d4bb2cbb9..a82ae58bb 100644 --- a/spec/Makefile +++ b/spec/Makefile @@ -12,9 +12,13 @@ BUILDDIR = _build help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -.PHONY: help Makefile +.PHONY: help Makefile clean # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +clean: + -rm -rf $(BUILDDIR) + -rm -rf "$(SOURCEDIR)/API_specification/generated" From 7597b740e0b41c889e0c2074eaee39ec812e57c5 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 17 Jan 2022 12:01:01 -0500 Subject: [PATCH 150/551] Fix rendering --- spec/API_specification/broadcasting.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/broadcasting.rst b/spec/API_specification/broadcasting.rst index 93a4519c6..58a49c768 100644 --- a/spec/API_specification/broadcasting.rst +++ b/spec/API_specification/broadcasting.rst @@ -49,15 +49,15 @@ The results of the element-wise operation must be stored in an array having a sh #. If ``d1 == 1``, then - - set the ``i``th element of ``shape`` to ``d2``. + - set the ``i``\th element of ``shape`` to ``d2``. #. Else, if ``d2 == 1``, then - - set the ``i``th element of ``shape`` to ``d1``. + - set the ``i``\th element of ``shape`` to ``d1``. #. Else, if ``d1 == d2``, then - - set the ``i``th element of ``shape`` to ``d1``. + - set the ``i``\th element of ``shape`` to ``d1``. #. Else, throw an exception. From d374b4cbc2038628dfd30b7ae8b249c2ddf8c67c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 17 Jan 2022 13:06:00 -0500 Subject: [PATCH 151/551] Add review changes --- spec/API_specification/data_types.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/data_types.rst b/spec/API_specification/data_types.rst index d645f9c58..f40006c4e 100644 --- a/spec/API_specification/data_types.rst +++ b/spec/API_specification/data_types.rst @@ -68,10 +68,11 @@ IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-20 Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. .. admonition:: Future extension + :class: admonition tip ``complex64`` and ``complex128`` data types are expected to be included in the next version of this standard and to have the following casting rules (will be added to :ref:`type-promotion`): - .. image:: /_static/images/dtype_promotion_complex.png + .. image:: /_static/images/dtype_promotion_complex.png See `array-api/issues/102 `_ for more details From 34dd8b9aef8029261706d052154d29c0a5ce33a4 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 17 Jan 2022 13:13:53 -0500 Subject: [PATCH 152/551] Fix identation of the note directive --- spec/API_specification/function_and_method_signatures.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/function_and_method_signatures.rst b/spec/API_specification/function_and_method_signatures.rst index 79115ed6e..86d0819a6 100644 --- a/spec/API_specification/function_and_method_signatures.rst +++ b/spec/API_specification/function_and_method_signatures.rst @@ -13,7 +13,7 @@ Function signatures in this standard adhere to the following: *Rationale: existing libraries have incompatible conventions, and using names of positional parameters is not normal/recommended practice.* -.. note:: + .. note:: Positional-only parameters are only available in Python >= 3.8. Libraries still supporting 3.7 or 3.6 may consider making the API standard-compliant From 6b590e0b7173b52036de703cd6e73349c7c89078 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 17 Jan 2022 13:27:26 -0500 Subject: [PATCH 153/551] Add review changes --- spec/API_specification/indexing.rst | 58 +++++++++++++++-------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/spec/API_specification/indexing.rst b/spec/API_specification/indexing.rst index 55523c007..889517ca6 100644 --- a/spec/API_specification/indexing.rst +++ b/spec/API_specification/indexing.rst @@ -18,25 +18,25 @@ To index a single array axis, an array must support standard Python indexing rul - **Valid** nonnegative indices must reside on the half-open interval ``[0, n)``. -.. note:: - This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. - Negative indices must count backward from the last array index, starting from ``-1`` (i.e., negative-one-based indexing, where ``-1`` refers to the last array index). -.. note:: - A negative index ``j`` is equivalent to ``n-j``; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. + .. note:: + A negative index ``j`` is equivalent to ``n-j``; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. - **Valid** negative indices must reside on the closed interval ``[-n, -1]``. -.. note:: - This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. - A negative index ``j`` is related to a zero-based nonnegative index ``i`` via ``i = n+j``. -- Colons ``:`` must be used for `slices `_: ``start:stop:step``, where ``start`` is inclusive and ``stop`` is exclusive. +- Colons ``:`` must be used for `slices `_: ``start:stop:step``, where ``start`` is inclusive and ``stop`` is exclusive. -.. note:: - The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. + .. note:: + The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. Slice Syntax ~~~~~~~~~~~~ @@ -106,8 +106,8 @@ Using a slice to index a single array axis must adhere to the following rules. L - Indexing via ``:`` and ``::`` must be equivalent and have defaults derived from the rules above. Both ``:`` and ``::`` indicate to select all elements along a single axis (dimension). -.. note:: - This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where ``0:100`` and ``0:10`` are equivalent on a list of length ``10``. + .. note:: + This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where ``0:100`` and ``0:10`` are equivalent on a list of length ``10``. The following ranges for the start and stop values of a slice must be supported. Let ``n`` be the axis (dimension) size being sliced. For a slice ``i:j:k``, the behavior specified above should be implemented for the following: @@ -128,19 +128,19 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., ``A[:, 2:10, :, 5]``). -.. note:: - In Python, ``A[(exp1, exp2, ..., expN)]`` is equivalent to ``A[exp1, exp2, ..., expN]``; the latter is syntactic sugar for the former. + .. note:: + In Python, ``A[(exp1, exp2, ..., expN)]`` is equivalent to ``A[exp1, exp2, ..., expN]``; the latter is syntactic sugar for the former. - Accordingly, if ``A`` has rank ``1``, then ``A[(2:10,)]`` must be equivalent to ``A[2:10]``. If ``A`` has rank ``2``, then ``A[(2:10, :)]`` must be equivalent to ``A[2:10, :]``. And so on and so forth. + Accordingly, if ``A`` has rank ``1``, then ``A[(2:10,)]`` must be equivalent to ``A[2:10]``. If ``A`` has rank ``2``, then ``A[(2:10, :)]`` must be equivalent to ``A[2:10, :]``. And so on and so forth. - Providing a single nonnegative integer ``i`` as a single-axis index must index the same elements as the slice ``i:i+1``. - Providing a single negative integer ``i`` as a single-axis index must index the same elements as the slice ``n+i:n+i+1``, where ``n`` is the axis (dimension) size. -- Providing a single integer as a single-axis index must reduce the number of array dimensions by ``1`` (i.e., the array rank should decrease by one; if ``A`` has rank ``2``, ``rank(A)-1 == rank(A[0, :])``). In particular, a selection tuple with the ``m``th element an integer (and all other entries ``:``) indexes a sub-array with rank ``N-1``. +- Providing a single integer as a single-axis index must reduce the number of array dimensions by ``1`` (i.e., the array rank should decrease by one; if ``A`` has rank ``2``, ``rank(A)-1 == rank(A[0, :])``). In particular, a selection tuple with the ``m``\th element an integer (and all other entries ``:``) indexes a sub-array with rank ``N-1``. -.. note:: - When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. + .. note:: + When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. - Providing a slice must retain array dimensions (i.e., the array rank must remain the same; ``rank(A) == rank(A[:])``). @@ -148,35 +148,37 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing an empty tuple or an ellipsis to an array of rank ``0`` must result in an array of the same rank (i.e., if ``A`` has rank ``0``, ``A == A[()]`` and ``A == A[...]``). -.. note:: - This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. + .. note:: + This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. - Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions is less than ``N``. -.. note:: - Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. + .. note:: + Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. - To perform flat indexing, use ``reshape(x, (-1,))[integer]``. + To perform flat indexing, use ``reshape(x, (-1,))[integer]``. - An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions is greater than ``N``. -.. note:: - This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. + .. note:: + This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. - *Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to* ``0`` *, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + *Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to* ``0`` *, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* Boolean Array Indexing ---------------------- -.. important:: Data-dependent output shape +.. admonition:: Data-dependent output shape + :class: admonition important + For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See :ref:`data-dependent-output-shapes` section for more details. An array must support indexing where the **sole index** is an ``M``-dimensional boolean array ``B`` with shape ``S1 = (s1, ..., sM)`` according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S2 = (s1, ..., sM, ..., sN)``. - If ``N >= M``, then ``A[B]`` must replace the first ``M`` dimensions of ``A`` with a single dimension having a size equal to the number of ``True`` elements in ``B``. The values in the resulting array must be in row-major (C-style order); this is equivalent to ``A[nonzero(B)]``. -.. note:: - For example, if ``N == M == 2``, indexing ``A`` via a boolean array ``B`` will return a one-dimensional array whose size is equal to the number of ``True`` elements in ``B``. + .. note:: + For example, if ``N == M == 2``, indexing ``A`` via a boolean array ``B`` will return a one-dimensional array whose size is equal to the number of ``True`` elements in ``B``. - If ``N < M``, then an ``IndexError`` exception must be raised. From 993423daa0ada4054f69f20c57894d3c947debc0 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 17 Jan 2022 14:39:00 -0500 Subject: [PATCH 154/551] Delete extra file --- spec/API_specification/array_object.md | 1357 ------------------------ 1 file changed, 1357 deletions(-) delete mode 100644 spec/API_specification/array_object.md diff --git a/spec/API_specification/array_object.md b/spec/API_specification/array_object.md deleted file mode 100644 index 46ba3648e..000000000 --- a/spec/API_specification/array_object.md +++ /dev/null @@ -1,1357 +0,0 @@ -(array-object)= - -# Array object - -> Array API specification for array object attributes and methods. - -A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods adhering to the following conventions. - -- Positional parameters must be [positional-only](https://www.python.org/dev/peps/pep-0570/) parameters. Positional-only parameters have no externally-usable name. When a method accepting positional-only parameters is called, positional arguments are mapped to these parameters based solely on their order. -- Optional parameters must be [keyword-only](https://www.python.org/dev/peps/pep-3102/) arguments. -- Broadcasting semantics must follow the semantics defined in {ref}`broadcasting`. -- Unless stated otherwise, methods must support the data types defined in {ref}`data-types`. -- Unless stated otherwise, methods must adhere to the type promotion rules defined in {ref}`type-promotion`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -Furthermore, a conforming implementation of the array API standard must support array objects of arbitrary rank `N` (i.e., number of dimensions), where `N` is greater than or equal to zero. - -```{note} -Conforming implementations must support zero-dimensional arrays. - -Apart from array object attributes, such as `ndim`, `device`, and `dtype`, all operations in this standard return arrays (or tuples of arrays), including those operations, such as `mean`, `var`, and `std`, from which some common array libraries (e.g., NumPy) return scalar values. - -_Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value._ -``` - -* * * - -(operators)= - -## Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. - -### Arithmetic Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. - -- `+x`: [`__pos__(x)`](#__pos__self-) - - - [`operator.pos(x)`](https://docs.python.org/3/library/operator.html#operator.pos) - - [`operator.__pos__(x)`](https://docs.python.org/3/library/operator.html#operator.__pos__) - -- `-x`: [`__neg__(x)`](#__neg__self-) - - - [`operator.neg(x)`](https://docs.python.org/3/library/operator.html#operator.neg) - - [`operator.__neg__(x)`](https://docs.python.org/3/library/operator.html#operator.__neg__) - -- `x1 + x2`: [`__add__(x1, x2)`](#__add__self-other-) - - - [`operator.add(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.add) - - [`operator.__add__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__add__) - -- `x1 - x2`: [`__sub__(x1, x2)`](#__sub__self-other-) - - - [`operator.sub(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.sub) - - [`operator.__sub__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__sub__) - -- `x1 * x2`: [`__mul__(x1, x2)`](#__mul__self-other-) - - - [`operator.mul(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.mul) - - [`operator.__mul__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__mul__) - -- `x1 / x2`: [`__truediv__(x1, x2)`](#__truediv__self-other-) - - - [`operator.truediv(x1,x2)`](https://docs.python.org/3/library/operator.html#operator.truediv) - - [`operator.__truediv__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__truediv__) - -- `x1 // x2`: [`__floordiv__(x1, x2)`](#__floordiv__self-other-) - - - [`operator.floordiv(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.floordiv) - - [`operator.__floordiv__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__floordiv__) - -- `x1 % x2`: [`__mod__(x1, x2)`](#__mod__self-other-) - - - [`operator.mod(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.mod) - - [`operator.__mod__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__mod__) - -- `x1 ** x2`: [`__pow__(x1, x2)`](#__pow__self-other-) - - - [`operator.pow(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.pow) - - [`operator.__pow__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__pow__) - -Arithmetic operators should be defined for arrays having numeric data types. - -### Array Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. - -- `x1 @ x2`: [`__matmul__(x1, x2)`](#__matmul__self-other-) - - - [`operator.matmul(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.matmul) - - [`operator.__matmul__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__matmul__) - -The matmul `@` operator should be defined for arrays having numeric data types. - -### Bitwise Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. - -- `~x`: [`__invert__(x)`](#__invert__self-) - - - [`operator.inv(x)`](https://docs.python.org/3/library/operator.html#operator.inv) - - [`operator.invert(x)`](https://docs.python.org/3/library/operator.html#operator.invert) - - [`operator.__inv__(x)`](https://docs.python.org/3/library/operator.html#operator.__inv__) - - [`operator.__invert__(x)`](https://docs.python.org/3/library/operator.html#operator.__invert__) - -- `x1 & x2`: [`__and__(x1, x2)`](#__and__self-other-) - - - [`operator.and(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.and) - - [`operator.__and__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__and__) - -- `x1 | x2`: [`__or__(x1, x2)`](#__or__self-other-) - - - [`operator.or(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.or) - - [`operator.__or__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__or__) - -- `x1 ^ x2`: [`__xor__(x1, x2)`](#__xor__self-other-) - - - [`operator.xor(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.xor) - - [`operator.__xor__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__xor__) - -- `x1 << x2`: [`__lshift__(x1, x2)`](#__lshift__self-other-) - - - [`operator.lshift(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.lshift) - - [`operator.__lshift__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__lshift__) - -- `x1 >> x2`: [`__rshift__(x1, x2)`](#__rshift__self-other-) - - - [`operator.rshift(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.rshift) - - [`operator.__rshift__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__rshift__) - -Bitwise operators should be defined for arrays having integer and boolean data types. - -### Comparison Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. - -- `x1 < x2`: [`__lt__(x1, x2)`](#__lt__self-other-) - - - [`operator.lt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.lt) - - [`operator.__lt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__lt__) - -- `x1 <= x2`: [`__le__(x1, x2)`](#__le__self-other-) - - - [`operator.le(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.le) - - [`operator.__le__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__le__) - -- `x1 > x2`: [`__gt__(x1, x2)`](#__gt__self-other-) - - - [`operator.gt(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.gt) - - [`operator.__gt__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__gt__) - -- `x1 >= x2`: [`__ge__(x1, x2)`](#__ge__self-other-) - - - [`operator.ge(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ge) - - [`operator.__ge__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ge__) - -- `x1 == x2`: [`__eq__(x1, x2)`](#__eq__self-other-) - - - [`operator.eq(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.eq) - - [`operator.__eq__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__eq__) - -- `x1 != x2`: [`__ne__(x1, x2)`](#__ne__self-other-) - - - [`operator.ne(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.ne) - - [`operator.__ne__(x1, x2)`](https://docs.python.org/3/library/operator.html#operator.__ne__) - -Comparison operators should be defined for arrays having any data type. - -### In-place Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. - -An in-place operation must not change the data type or shape of the in-place array as a result of {ref}`type-promotion` or {ref}`broadcasting`. - -An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition `x1 += x2`, the modified array `x1` must always equal the result of the equivalent binary arithmetic operation `x1 = x1 + x2`. - -```{note} -In-place operators must be supported as discussed in {ref}`copyview-mutability`. -``` - -#### Arithmetic Operators - -- `+=`. May be implemented via `__iadd__`. -- `-=`. May be implemented via `__isub__`. -- `*=`. May be implemented via `__imul__`. -- `/=`. May be implemented via `__itruediv__`. -- `//=`. May be implemented via `__ifloordiv__`. -- `**=`. May be implemented via `__ipow__`. -- `%=`. May be implemented via `__imod__`. - -#### Array Operators - -- `@=`. May be implemented via `__imatmul__`. - -#### Bitwise Operators - -- `&=`. May be implemented via `__iand__`. -- `|=`. May be implemented via `__ior__`. -- `^=`. May be implemented via `__ixor__`. -- `<<=`. May be implemented via `__ilshift__`. -- `>>=`. May be implemented via `__irshift__`. - -### Reflected Operators - -A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. - -The results of applying reflected operators must match their non-reflected equivalents. - -```{note} -All operators for which `array scalar` is implemented must have an equivalent reflected operator implementation. -``` - -#### Arithmetic Operators - -- `__radd__` -- `__rsub__` -- `__rmul__` -- `__rtruediv__` -- `__rfloordiv__` -- `__rpow__` -- `__rmod__` - -#### Array Operators - -- `__rmatmul__` - -#### Bitwise Operators - -- `__rand__` -- `__ror__` -- `__rxor__` -- `__rlshift__` -- `__rrshift__` - -* * * - -## Attributes - - - -(attribute-dtype)= -### dtype - -Data type of the array elements. - -#### Returns - -- **out**: _<dtype>_ - - - array data type. - -(attribute-device)= -### device - -Hardware device the array data resides on. - -#### Returns - -- **out**: _<device>_ - - - a `device` object (see {ref}`device-support`). - -(attribute-mT)= -### mT - -Transpose of a matrix (or a stack of matrices). - -If an array instance has fewer than two dimensions, an error should be raised. - -#### Returns - -- **out**: _<array>_ - - - array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape `(..., M, N)`, the returned array must have shape `(..., N, M)`). The returned array must have the same data type as the original array. - -(attribute-ndim)= -### ndim - -Number of array dimensions (axes). - -#### Returns - -- **out**: _int_ - - - number of array dimensions (axes). - -(attribute-shape)= -### shape - -Array dimensions. - -#### Returns - -- **out**: _Tuple\[ Optional\[ int ], ... ]_ - - - array dimensions. An array dimension must be `None` if and only if a dimension is unknown. - -```{note} -For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; `A[:, B > 0]`) and thus cannot be statically resolved without knowing array contents. -``` - -```{note} -The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. -``` - -(attribute-size)= -### size - -Number of elements in an array. - -```{note} -This must equal the product of the array's dimensions. -``` - -#### Returns - -- **out**: _Optional\[ int ]_ - - - number of elements in an array. The returned value must be `None` if and only if one or more array dimensions are unknown. - -```{note} -For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. -``` - -(attribute-T)= -### T - -Transpose of the array. - -The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. - -```{note} -Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional `permute_dims` interface found in this specification. -``` - -#### Returns - -- **out**: _<array>_ - - - two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. - -* * * - -## Methods - - - -(method-__abs__)= -### \_\_abs\_\_(self, /) - -Calculates the absolute value for each element of an array instance (i.e., the element-wise result has the same magnitude as the respective element but has positive sign). - -```{note} -For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. -``` - -#### Special Cases - -For floating-point operands, let `self` equal `x`. - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `-0`, the result is `+0`. -- If `x_i` is `-infinity`, the result is `+infinity`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise absolute value. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`abs(x)`](elementwise_functions.md#absx-). -``` - -(method-__add__)= -### \_\_add\_\_(self, other, /) - -Calculates the sum for each element of an array instance with the respective element of the array `other`. - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is `+infinity` and `x2_i` is `-infinity`, the result is `NaN`. -- If `x1_i` is `-infinity` and `x2_i` is `+infinity`, the result is `NaN`. -- If `x1_i` is `+infinity` and `x2_i` is `+infinity`, the result is `+infinity`. -- If `x1_i` is `-infinity` and `x2_i` is `-infinity`, the result is `-infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a finite number, the result is `+infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a finite number, the result is `-infinity`. -- If `x1_i` is a finite number and `x2_i` is `+infinity`, the result is `+infinity`. -- If `x1_i` is a finite number and `x2_i` is `-infinity`, the result is `-infinity`. -- If `x1_i` is `-0` and `x2_i` is `-0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is `+0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `-0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `+0`, the result is `+0`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is a nonzero finite number, the result is `x2_i`. -- If `x1_i` is a nonzero finite number and `x2_i` is either `+0` or `-0`, the result is `x1_i`. -- If `x1_i` is a nonzero finite number and `x2_i` is `-x1_i`, the result is `+0`. -- In the remaining cases, when neither `infinity`, `+0`, `-0`, nor a `NaN` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. - -```{note} -Floating-point addition is a commutative operation, but not always associative. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance (augend array). Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - addend array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise sums. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`add(x1, x2)`](elementwise_functions.md#addx1-x2-). -``` - -(method-__and__)= -### \_\_and\_\_(self, other, /) - -Evaluates `self_i & other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -- **other**: _Union\[ int, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_and(x1, x2)`](elementwise_functions.md#logical_andx1-x2-). -``` - - -(method-__array_namespace__)= -### \_\_array_namespace\_\_(self, /, *, api_version=None) - -Returns an object that has all the array API functions on it. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **api_version**: _<Optional\[str\]>_ - - - string representing the version of the array API specification to be returned, in `'YYYY.MM'` form, for example, `'2020.10'`. If it is `None`, it should return the namespace corresponding to latest version of the array API specification. If the given version is invalid or not implemented for the given module, an error should be raised. Default: `None`. - -#### Returns - -- **out**: _<Any>_ - - - an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. - - -(method-__bool__)= -### \_\_bool\_\_(self, /) - -Converts a zero-dimensional boolean array to a Python `bool` object. - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have a boolean data type. - -#### Returns - -- **out**: _<bool>_ - - - a Python `bool` object representing the single element of the array. - - -(method-__dlpack__)= -### \_\_dlpack\_\_(self, /, *, stream=None) - -Exports the array for consumption by {ref}`function-from_dlpack` as a DLPack capsule. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **stream**: _Optional\[ Union\[ int, Any ]]_ - - - for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. `stream` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be a positive integer or `-1`. If `stream` is `-1`, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. - - On CPU and other device types without streams, only `None` is accepted. - - For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for `stream` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order `cl::sycl::queue`. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. - - ```{note} - Support for a `stream` value other than `None` is optional and implementation-dependent. - ``` - - Device-specific notes: - - :::{admonition} CUDA - - `None`: producer must assume the legacy default stream (default). - - `1`: the legacy default stream. - - `2`: the per-thread default stream. - - `> 2`: stream number represented as a Python integer. - - `0` is disallowed due to its ambiguity: `0` could mean either `None`, `1`, or `2`. - ::: - - :::{admonition} ROCm - - `None`: producer must assume the legacy default stream (default). - - `0`: the default stream. - - `> 2`: stream number represented as a Python integer. - - Using `1` and `2` is not supported. - ::: - - ```{tip} - It is recommended that implementers explicitly handle streams. If - they use the legacy default stream, specifying `1` (CUDA) or `0` - (ROCm) is preferred. `None` is a safe default for developers who do - not want to think about stream handling at all, potentially at the - cost of more synchronization than necessary. - ``` - -#### Returns - -- **capsule**: _<PyCapsule>_ - - - a DLPack capsule for the array. See {ref}`data-interchange` for details. - - -(method-__dlpack_device__)= -### \_\_dlpack\_device\_\_(self, /) - -Returns device type and device ID in DLPack format. Meant for use within {ref}`function-from_dlpack`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -#### Returns - -- **device**: _Tuple\[enum.IntEnum, int\]_ - - - a tuple `(device_type, device_id)` in DLPack format. Valid device type enum members are: - - ``` - CPU = 1 - CUDA = 2 - CPU_PINNED = 3 - OPENCL = 4 - VULKAN = 7 - METAL = 8 - VPI = 9 - ROCM = 10 - ``` - -(method-__eq__)= -### \_\_eq\_\_(self, other, /) - -Computes the truth value of `self_i == other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. May have any data type. - -- **other**: _Union\[ int, float, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). May have any data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`equal(x1, x2)`](elementwise_functions.md#equalx1-x2-). -``` - -(method-__float__)= -### \_\_float\_\_(self, /) - -Converts a zero-dimensional floating-point array to a Python `float` object. - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have a floating-point data type. - -#### Returns - -- **out**: _<float>_ - - - a Python `float` object representing the single element of the array instance. - -(method-__floordiv__)= -### \_\_floordiv\_\_(self, other, /) - -Evaluates `self_i // other_i` for each element of an array instance with the respective element of the array `other`. - -```{note} -For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. -``` - -#### Special Cases - -```{note} -Floor division was introduced in Python via [PEP 238](https://www.python.org/dev/peps/pep-0238/) with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a `float`, while the latter was computed when both operands were `int`s. Overloading the `/` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. - -To resolve this ambiguity, `/` was designated for true division, and `//` was designated for floor division. Semantically, floor division was [defined](https://www.python.org/dev/peps/pep-0238/#semantics-of-floor-division) as equivalent to `a // b == floor(a/b)`; however, special floating-point cases were left ill-defined. - -Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is `infinity`, libraries may diverge with some choosing to strictly follow `floor(a/b)` and others choosing to pair `//` with `%` according to the relation `b = a % b + b * (a // b)`. The special cases leading to divergent behavior are documented below. - -This specification prefers floor division to match `floor(divide(x1, x2))` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. -``` - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. -- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. -- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. -- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`floor_divide(x1, x2)`](elementwise_functions.md#floor_dividex1-x2-). -``` - -(method-__ge__)= -### \_\_ge\_\_(self, other, /) - -Computes the truth value of `self_i >= other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`greater_equal(x1, x2)`](elementwise_functions.md#greater_equalx1-x2-). -``` - -(method-__getitem__)= -### \_\_getitem\_\_(self, key, /) - -Returns `self[key]`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **key**: _Union\[ int, slice, ellipsis, Tuple\[ Union\[ int, slice, ellipsis ], ... ], <array> ]_ - - - index key. - -#### Returns - -- **out**: _<array>_ - - - an array containing the accessed value(s). The returned array must have the same data type as `self`. - -(method-__gt__)= -### \_\_gt\_\_(self, other, /) - -Computes the truth value of `self_i > other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`greater(x1, x2)`](elementwise_functions.md#greaterx1-x2-). -``` - -(method-__index__)= -### \_\_index\_\_(self, /) - -Converts a zero-dimensional integer array to a Python `int` object. - -```{note} -This method is called to implement [`operator.index()`](https://docs.python.org/3/reference/datamodel.html#object.__index__). See also [PEP 357](https://www.python.org/dev/peps/pep-0357/). -``` - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have an integer data type. - -#### Returns - -- **out**: _<int>_ - - - a Python `int` object representing the single element of the array instance. - -(method-__int__)= -### \_\_int\_\_(self, /) - -Converts a zero-dimensional integer array to a Python `int` object. - -#### Parameters - -- **self**: _<array>_ - - - zero-dimensional array instance. Must have an integer data type. - -#### Returns - -- **out**: _<int>_ - - - a Python `int` object representing the single element of the array instance. - -(method-__invert__)= -### \_\_invert\_\_(self, /) - -Evaluates `~self_i` for each element of an array instance. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_invert(x)`](elementwise_functions.md#bitwise_invertx-). -``` - -(method-__le__)= -### \_\_le\_\_(self, other, /) - -Computes the truth value of `self_i <= other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`less_equal(x1, x2)`](elementwise_functions.md#less_equalx1-x2-). -``` - -(method-__lshift__)= -### \_\_lshift\_\_(self, other, /) - -Evaluates `self_i << other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer data type. - -- **other**: _Union\[ int, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer data type. Each element must be greater than or equal to `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_left_shift(x1, x2)`](elementwise_functions.md#bitwise_left_shiftx1-x2-). -``` - -(method-__lt__)= -### \_\_lt\_\_(self, other, /) - -Computes the truth value of `self_i < other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`less(x1, x2)`](elementwise_functions.md#lessx1-x2-). -``` - -(method-__matmul__)= -### \_\_matmul\_\_(self, other, /) - -Computes the matrix product. - -```{note} -The `matmul` function must implement the same semantics as the built-in `@` operator (see [PEP 465](https://www.python.org/dev/peps/pep-0465)). -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. Must have at least one dimension. If `self` is one-dimensional having shape `(M,)` and `other` has more than one dimension, `self` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `self` has more than one dimension (including after vector-to-matrix promotion), `shape(self)[:-2]` must be compatible with `shape(other)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `self` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - -- **other**: _<array>_ - - - other array. Should have a numeric data type. Must have at least one dimension. If `other` is one-dimensional having shape `(N,)` and `self` has more than one dimension, `other` must be promoted to a two-dimensional array by appending `1` to its dimensions (i.e., must have shape `(N, 1)`). After matrix multiplication, the appended dimensions in the returned array must be removed. If `other` has more than one dimension (including after vector-to-matrix promotion), `shape(other)[:-2]` must be compatible with `shape(self)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `other` has shape `(..., K, N)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - -#### Returns - -- **out**: _<array>_ - - - if both `self` and `other` are one-dimensional arrays having shape `(N,)`, a zero-dimensional array containing the inner product as its only element. - - if `self` is a two-dimensional array having shape `(M, K)` and `other` is a two-dimensional array having shape `(K, N)`, a two-dimensional array containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) and having shape `(M, N)`. - - if `self` is a one-dimensional array having shape `(K,)` and `other` is an array having shape `(..., K, N)`, an array having shape `(..., N)` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `self` is an array having shape `(..., M, K)` and `other` is a one-dimensional array having shape `(K,)`, an array having shape `(..., M)` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `self` is a two-dimensional array having shape `(M, K)` and `other` is an array having shape `(..., K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if `self` is an array having shape `(..., M, K)` and `other` is a two-dimensional array having shape `(K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if either `self` or `other` has more than two dimensions, an array having a shape determined by {ref}`broadcasting` `shape(self)[:-2]` against `shape(other)[:-2]` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - The returned array must have a data type determined by {ref}`type-promotion`. - - ```{note} - Results must equal the results returned by the equivalent function [`matmul(x1, x2)`](linear_algebra_functions.md#matmulx1-x2-). - ``` - -#### Raises - -- if either `self` or `other` is a zero-dimensional array. -- if `self` is a one-dimensional array having shape `(K,)`, `other` is a one-dimensional array having shape `(L,)`, and `K != L`. -- if `self` is a one-dimensional array having shape `(K,)`, `other` is an array having shape `(..., L, N)`, and `K != L`. -- if `self` is an array having shape `(..., M, K)`, `other` is a one-dimensional array having shape `(L,)`, and `K != L`. -- if `self` is an array having shape `(..., M, K)`, `other` is an array having shape `(..., L, N)`, and `K != L`. - -(method-__mod__)= -### \_\_mod\_\_(self, other, /) - -Evaluates `self_i % other_i` for each element of an array instance with the respective element of the array `other`. - -```{note} -For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element `other_i`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`remainder(x1, x2)`](elementwise_functions.md#remainderx1-x2-). -``` - -(method-__mul__)= -### \_\_mul\_\_(self, other, /) - -Calculates the product for each element of an array instance with the respective element of the array `other`. - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` and `x2_i` have the same mathematical sign, the result has a positive mathematical sign, unless the result is `NaN`. If the result is `NaN`, the "sign" of `NaN` is implementation-defined. -- If `x1_i` and `x2_i` have different mathematical signs, the result has a negative mathematical sign, unless the result is `NaN`. If the result is `NaN`, the "sign" of `NaN` is implementation-defined. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- If `x1_i` is a nonzero finite number and `x2_i` is either `+infinity` or `-infinity`, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- In the remaining cases, where neither `infinity` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. - -```{note} -Floating-point multiplication is not always associative due to finite precision. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise products. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`multiply(x1, x2)`](elementwise_functions.md#multiplyx1-x2-). -``` - -(method-__ne__)= -### \_\_ne\_\_(self, other, /) - -Computes the truth value of `self_i != other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. May have any data type. - -- **other**: _Union\[ int, float, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). May have any data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool` (i.e., must be a boolean array). - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`not_equal(x1, x2)`](elementwise_functions.md#not_equalx1-x2-). -``` - -(method-__neg__)= -### \_\_neg\_\_(self, /) - -Evaluates `-self_i` for each element of an array instance. - -```{note} -For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. -``` - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `self`. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`negative(x)`](elementwise_functions.md#negativex-). -``` - -(method-__or__)= -### \_\_or\_\_(self, other, /) - -Evaluates `self_i | other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -- **other**: _Union\[ int, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_or(x1, x2)`](elementwise_functions.md#bitwise_orx1-x2-). -``` - -(method-__pos__)= -### \_\_pos\_\_(self, /) - -Evaluates `+self_i` for each element of an array instance. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`positive(x)`](elementwise_functions.md#positivex-). -``` - -(method-__pow__)= -### \_\_pow\_\_(self, other, /) - -Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of `other_i` (the exponent), where `other_i` is the corresponding element of the array `other`. - -```{note} -If both `self` and `other` have integer data types, the result of `__pow__` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - -If `self` has an integer data type and `other` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. -``` - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If `x1_i` is not equal to `1` and `x2_i` is `NaN`, the result is `NaN`. -- If `x2_i` is `+0`, the result is `1`, even if `x1_i` is `NaN`. -- If `x2_i` is `-0`, the result is `1`, even if `x1_i` is `NaN`. -- If `x1_i` is `NaN` and `x2_i` is not equal to `0`, the result is `NaN`. -- If `abs(x1_i)` is greater than `1` and `x2_i` is `+infinity`, the result is `+infinity`. -- If `abs(x1_i)` is greater than `1` and `x2_i` is `-infinity`, the result is `+0`. -- If `abs(x1_i)` is `1` and `x2_i` is `+infinity`, the result is `1`. -- If `abs(x1_i)` is `1` and `x2_i` is `-infinity`, the result is `1`. -- If `x1_i` is `1` and `x2_i` is not `NaN`, the result is `1`. -- If `abs(x1_i)` is less than `1` and `x2_i` is `+infinity`, the result is `+0`. -- If `abs(x1_i)` is less than `1` and `x2_i` is `-infinity`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is greater than `0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is an odd integer value, the result is `-infinity`. -- If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is not an odd integer value, the result is `+infinity`. -- If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is an odd integer value, the result is `-0`. -- If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is not an odd integer value, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `+infinity`. -- If `x1_i` is `-0`, `x2_i` is greater than `0`, and `x2_i` is an odd integer value, the result is `-0`. -- If `x1_i` is `-0`, `x2_i` is greater than `0`, and `x2_i` is not an odd integer value, the result is `+0`. -- If `x1_i` is `-0`, `x2_i` is less than `0`, and `x2_i` is an odd integer value, the result is `-infinity`. -- If `x1_i` is `-0`, `x2_i` is less than `0`, and `x2_i` is not an odd integer value, the result is `+infinity`. -- If `x1_i` is less than `0`, `x1_i` is a finite number, `x2_i` is a finite number, and `x2_i` is not an integer value, the result is `NaN`. - -#### Parameters - -- **self**: _<array>_ - - - array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array whose elements correspond to the exponentiation exponent. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`pow(x1, x2)`](elementwise_functions.md#powx1-x2-). -``` - -(method-__rshift__)= -### \_\_rshift\_\_(self, other, /) - -Evaluates `self_i >> other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer data type. - -- **other**: _Union\[ int, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer data type. Each element must be greater than or equal to `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have the same data type as `self`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_right_shift(x1, x2)`](elementwise_functions.md#bitwise_right_shiftx1-x2-). -``` - -(method-__setitem__)= -### \_\_setitem\_\_(self, key, value, /) - -Sets `self[key]` to `value`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **key**: _Union\[ int, slice, ellipsis, Tuple\[ Union\[ int, slice, ellipsis ], ... ], <array> ]_ - - - index key. - -- **value**: _Union\[ int, float, bool, <array> ]_ - - - value(s) to set. Must be compatible with `self[key]` (see {ref}`broadcasting`). - -```{note} -Setting array values must not affect the data type of `self`. - -When `value` is a Python scalar (i.e., `int`, `float`, `bool`), behavior must follow specification guidance on mixing arrays with Python scalars (see {ref}`type-promotion`). - -When `value` is an `array` of a different data type than `self`, how values are cast to the data type of `self` is implementation defined. -``` - -(method-__sub__)= -### \_\_sub\_\_(self, other, /) - -Calculates the difference for each element of an array instance with the respective element of the array `other`. The result of `self_i - other_i` must be the same as `self_i + (-other_i)` and must be governed by the same floating-point rules as addition (see [`__add__()`](#__add__self-other-)). - -#### Parameters - -- **self**: _<array>_ - - - array instance (minuend array). Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - subtrahend array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise differences. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`subtract(x1, x2)`](elementwise_functions.md#subtractx1-x2-). -``` - -(method-__truediv__)= -### \_\_truediv\_\_(self, other, /) - -Evaluates `self_i / other_i` for each element of an array instance with the respective element of the array `other`. - -```{note} -If one or both of `self` and `other` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - -Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. -``` - -#### Special Cases - -For floating-point operands, let `self` equal `x1` and `other` equal `x2`. - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. -- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. -- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. -- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have a numeric data type. - -- **other**: _Union\[ int, float, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array should have a floating-point data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`divide(x1, x2)`](elementwise_functions.md#dividex1-x2-). -``` - -(method-__xor__)= -### \_\_xor\_\_(self, other, /) - -Evaluates `self_i ^ other_i` for each element of an array instance with the respective element of the array `other`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. Should have an integer or boolean data type. - -- **other**: _Union\[ int, bool, <array> ]_ - - - other array. Must be compatible with `self` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -```{note} -Element-wise results must equal the results returned by the equivalent element-wise function [`bitwise_xor(x1, x2)`](elementwise_functions.md#bitwise_xorx1-x2-). -``` - -(method-to_device)= -### to\_device(self, device, /, *, stream=None) - -Copy the array from the device on which it currently resides to the specified `device`. - -#### Parameters - -- **self**: _<array>_ - - - array instance. - -- **device**: _<device>_ - - - a `device` object (see {ref}`device-support`). - -- **stream**: _Optional\[ Union\[ int, Any ]]_ - - - stream object to use during copy. In addition to the types supported in {ref}`method-__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. - -#### Returns - -- **out**: _<array>_ - - - an array with the same data and data type as `self` and located on the specified `device`. - -```{note} -If `stream` is given, the copy operation should be enqueued on the provided `stream`; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. -``` From fbddbd087c62d3947d2a00f91ff69441833a9ab7 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 18 Jan 2022 12:10:15 -0500 Subject: [PATCH 155/551] Fix nested list --- spec/API_specification/broadcasting.rst | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/spec/API_specification/broadcasting.rst b/spec/API_specification/broadcasting.rst index 58a49c768..ec72fb089 100644 --- a/spec/API_specification/broadcasting.rst +++ b/spec/API_specification/broadcasting.rst @@ -39,29 +39,27 @@ The results of the element-wise operation must be stored in an array having a sh #. Repeat, while ``i >= 0`` - #. Let ``n1`` be ``N1 - N + i``. + #. Let ``n1`` be ``N1 - N + i``. - #. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. + #. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. - #. Let ``n2`` be ``N2 - N + i``. + #. Let ``n2`` be ``N2 - N + i``. - #. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. + #. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. - #. If ``d1 == 1``, then + #. If ``d1 == 1``, then set the ``i``\th element of ``shape`` to ``d2``. - - set the ``i``\th element of ``shape`` to ``d2``. + #. Else, if ``d2 == 1``, then - #. Else, if ``d2 == 1``, then + - set the ``i``\th element of ``shape`` to ``d1``. - - set the ``i``\th element of ``shape`` to ``d1``. + #. Else, if ``d1 == d2``, then - #. Else, if ``d1 == d2``, then + - set the ``i``\th element of ``shape`` to ``d1``. - - set the ``i``\th element of ``shape`` to ``d1``. + #. Else, throw an exception. - #. Else, throw an exception. - - #. Set ``i`` to ``i-1``. + #. Set ``i`` to ``i-1``. #. Let ``tuple(shape)`` be the shape of the result array. From db4ee5e36ffa526c9eff989cf4ca13d84cfd26d1 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 19 Jan 2022 00:28:27 -0500 Subject: [PATCH 156/551] Transform linear algebra functions md to rst --- .../linear_algebra_functions.md | 142 ------------------ .../linear_algebra_functions.rst | 29 ++++ .../signatures/linear_algebra_functions.py | 112 ++++++++++++++ 3 files changed, 141 insertions(+), 142 deletions(-) delete mode 100644 spec/API_specification/linear_algebra_functions.md create mode 100644 spec/API_specification/linear_algebra_functions.rst create mode 100644 spec/API_specification/signatures/linear_algebra_functions.py diff --git a/spec/API_specification/linear_algebra_functions.md b/spec/API_specification/linear_algebra_functions.md deleted file mode 100644 index ce911de6e..000000000 --- a/spec/API_specification/linear_algebra_functions.md +++ /dev/null @@ -1,142 +0,0 @@ -# Linear Algebra Functions - -> Array API specification for linear algebra functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -## Objects in API - - - -(function-matmul)= -### matmul(x1, x2, /) - -Computes the matrix product. - -```{note} - -The `matmul` function must implement the same semantics as the built-in `@` operator (see [PEP 465](https://www.python.org/dev/peps/pep-0465)). -``` - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. Must have at least one dimension. If `x1` is one-dimensional having shape `(M,)` and `x2` has more than one dimension, `x1` must be promoted to a two-dimensional array by prepending `1` to its dimensions (i.e., must have shape `(1, M)`). After matrix multiplication, the prepended dimensions in the returned array must be removed. If `x1` has more than one dimension (including after vector-to-matrix promotion), `shape(x1)[:-2]` must be compatible with `shape(x2)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `x1` has shape `(..., M, K)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - -- **x2**: _<array>_ - - - second input array. Should have a numeric data type. Must have at least one dimension. If `x2` is one-dimensional having shape `(N,)` and `x1` has more than one dimension, `x2` must be promoted to a two-dimensional array by appending `1` to its dimensions (i.e., must have shape `(N, 1)`). After matrix multiplication, the appended dimensions in the returned array must be removed. If `x2` has more than one dimension (including after vector-to-matrix promotion), `shape(x2)[:-2]` must be compatible with `shape(x1)[:-2]` (after vector-to-matrix promotion) (see {ref}`broadcasting`). If `x2` has shape `(..., K, N)`, the innermost two dimensions form matrices on which to perform matrix multiplication. - -#### Returns - -- **out**: _<array>_ - - - if both `x1` and `x2` are one-dimensional arrays having shape `(N,)`, a zero-dimensional array containing the inner product as its only element. - - if `x1` is a two-dimensional array having shape `(M, K)` and `x2` is a two-dimensional array having shape `(K, N)`, a two-dimensional array containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) and having shape `(M, N)`. - - if `x1` is a one-dimensional array having shape `(K,)` and `x2` is an array having shape `(..., K, N)`, an array having shape `(..., N)` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `x1` is an array having shape `(..., M, K)` and `x2` is a one-dimensional array having shape `(K,)`, an array having shape `(..., M)` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication). - - if `x1` is a two-dimensional array having shape `(M, K)` and `x2` is an array having shape `(..., K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if `x1` is an array having shape `(..., M, K)` and `x2` is a two-dimensional array having shape `(K, N)`, an array having shape `(..., M, N)` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - if either `x1` or `x2` has more than two dimensions, an array having a shape determined by {ref}`broadcasting` `shape(x1)[:-2]` against `shape(x2)[:-2]` and containing the [conventional matrix product](https://en.wikipedia.org/wiki/Matrix_multiplication) for each stacked matrix. - - The returned array must have a data type determined by {ref}`type-promotion`. - -#### Raises - -- if either `x1` or `x2` is a zero-dimensional array. -- if `x1` is a one-dimensional array having shape `(K,)`, `x2` is a one-dimensional array having shape `(L,)`, and `K != L`. -- if `x1` is a one-dimensional array having shape `(K,)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. -- if `x1` is an array having shape `(..., M, K)`, `x2` is a one-dimensional array having shape `(L,)`, and `K != L`. -- if `x1` is an array having shape `(..., M, K)`, `x2` is an array having shape `(..., L, N)`, and `K != L`. - -(function-matrix-transpose)= -### matrix_transpose(x, /) - -Transposes a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. - -#### Returns - -- **out**: _<array>_ - - - an array containing the transpose for each matrix and having shape `(..., N, M)`. The returned array must have the same data type as `x`. - -(function-tensordot)= -### tensordot(x1, x2, /, *, axes=2) - -Returns a tensor contraction of `x1` and `x2` over specific axes. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` for all non-contracted axes (see {ref}`broadcasting`). Should have a numeric data type. - - ```{note} - Contracted axes (dimensions) must not be broadcasted. - ``` - -- **axes**: _Union\[ int, Tuple\[ Sequence\[ int ], Sequence\[ int ] ] ]_ - - - number of axes (dimensions) to contract or explicit sequences of axes (dimensions) for `x1` and `x2`, respectively. - - If `axes` is an `int` equal to `N`, then contraction must be performed over the last `N` axes of `x1` and the first `N` axes of `x2` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. - - - If `N` equals `0`, the result is the tensor (outer) product. - - If `N` equals `1`, the result is the tensor dot product. - - If `N` equals `2`, the result is the tensor double contraction (default). - - If `axes` is a tuple of two sequences `(x1_axes, x2_axes)`, the first sequence must apply to `x` and the second sequence to `x2`. Both sequences must have the same length. Each axis (dimension) `x1_axes[i]` for `x1` must have the same size as the respective axis (dimension) `x2_axes[i]` for `x2`. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. - -#### Returns - -- **out**: _<array>_ - - - an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array `x1`, followed by the non-contracted axes (dimensions) of the second array `x2`. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-vecdot)= -### vecdot(x1, x2, /, *, axis=-1) - -Computes the (vector) dot product of two arrays. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -- **axis**: _int_ - - - axis over which to compute the dot product. Must be an integer on the interval `[-N, N)`, where `N` is the rank (number of dimensions) of the shape determined according to {ref}`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where `-1` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: `-1`. - -#### Returns - -- **out**: _<array>_ - - - if `x1` and `x2` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank `N-1`, where `N` is the rank (number of dimensions) of the shape determined according to {ref}`broadcasting`. The returned array must have a data type determined by {ref}`type-promotion`. - -#### Raises - -- if provided an invalid `axis`. -- if the size of the axis over which to compute the dot product is not the same for both `x1` and `x2`. diff --git a/spec/API_specification/linear_algebra_functions.rst b/spec/API_specification/linear_algebra_functions.rst new file mode 100644 index 000000000..c12144aa4 --- /dev/null +++ b/spec/API_specification/linear_algebra_functions.rst @@ -0,0 +1,29 @@ +Linear Algebra Functions +======================== + + Array API specification for linear algebra functions. + +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`. +* Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. + +.. currentmodule:: signatures.linear_algebra_functions + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + matmul + matrix_transpose + tensordot + vecdot diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/spec/API_specification/signatures/linear_algebra_functions.py new file mode 100644 index 000000000..1fe4e65ec --- /dev/null +++ b/spec/API_specification/signatures/linear_algebra_functions.py @@ -0,0 +1,112 @@ +from ._types import Tuple, Union, array +from collections.abc import Sequence + +def matmul(x1: array, x2: array, /) -> array: + """ + Computes the matrix product. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + x2: array + second input array. Should have a numeric data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + Returns + ------- + out: array + - if both ``x1`` and ``x2`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``x1`` is a one-dimensional array having shape ``(K,)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``x1`` or ``x2`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(x1)[:-2]`` against ``shape(x2)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + + The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + **Raises** + + - if either ``x1`` or ``x2`` is a zero-dimensional array. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + """ + +def matrix_transpose(x: array, /) -> array: + """ + Transposes a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + + Returns + ------- + out: array + an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. + """ + +def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + """ + Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). Should have a numeric data type. + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] + number of axes (dimensions) to contract or explicit sequences of axes (dimensions) for ``x1`` and ``x2``, respectively. + + If ``axes`` is an ``int`` equal to ``N``, then contraction must be performed over the last ``N`` axes of ``x1`` and the first ``N`` axes of ``x2`` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. + + - If ``N`` equals ``0``, the result is the tensor (outer) product. + - If ``N`` equals ``1``, the result is the tensor dot product. + - If ``N`` equals ``2``, the result is the tensor double contraction (default). + + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + + Returns + ------- + out: array + an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + - Contracted axes (dimensions) must not be broadcasted. + """ + +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: + """ + Computes the (vector) dot product of two arrays. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + axis:int + axis over which to compute the dot product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. The returned array must have a data type determined by :ref:`type-promotion`. + + + **Raises** + + - if provided an invalid ``axis``. + - if the size of the axis over which to compute the dot product is not the same for both ``x1`` and ``x2``. + """ + +__all__ = ['matmul', 'matrix_transpose', 'tensordot', 'vecdot'] From dc946daa38b08c1b2a75445abcb2c887974c7f8b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 19 Jan 2022 16:34:47 -0500 Subject: [PATCH 157/551] Transform utility functions md to rst --- .../signatures/utility_functions.py | 41 ++++++++++++ spec/API_specification/utility_functions.md | 66 ------------------- spec/API_specification/utility_functions.rst | 27 ++++++++ 3 files changed, 68 insertions(+), 66 deletions(-) create mode 100644 spec/API_specification/signatures/utility_functions.py delete mode 100644 spec/API_specification/utility_functions.md create mode 100644 spec/API_specification/utility_functions.rst diff --git a/spec/API_specification/signatures/utility_functions.py b/spec/API_specification/signatures/utility_functions.py new file mode 100644 index 000000000..1b0a9bf2d --- /dev/null +++ b/spec/API_specification/signatures/utility_functions.py @@ -0,0 +1,41 @@ +from ._types import Optional, Tuple, Union, array + +def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + """ + Tests whether all input array elements evaluate to ``True`` along a specified axis. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical AND reduction. By default, a logical AND reduction must be performed over the entire array. If a tuple of integers, logical AND reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + """ + +def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + """ + Tests whether any input array element evaluates to ``True`` along a specified axis. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical OR reduction. By default, a logical OR reduction must be performed over the entire array. If a tuple of integers, logical OR reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + """ + +__all__ = ['all', 'any'] diff --git a/spec/API_specification/utility_functions.md b/spec/API_specification/utility_functions.md deleted file mode 100644 index aad65a71b..000000000 --- a/spec/API_specification/utility_functions.md +++ /dev/null @@ -1,66 +0,0 @@ -# Utility Functions - -> Array API specification for utility functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -## Objects in API - - - -(function-all)= -### all(x, /, *, axis=None, keepdims=False) - -Tests whether all input array elements evaluate to `True` along a specified axis. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which to perform a logical AND reduction. By default, a logical AND reduction must be performed over the entire array. If a tuple of integers, logical AND reductions must be performed over multiple axes. A valid `axis` must be an integer on the interval `[-N, N)`, where `N` is the rank (number of dimensions) of `x`. If an `axis` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where `-1` refers to the last dimension). If provided an invalid `axis`, the function must raise an exception. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of `bool`. - -(function-any)= -### any(x, /, *, axis=None, keepdims=False) - -Tests whether any input array element evaluates to `True` along a specified axis. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which to perform a logical OR reduction. By default, a logical OR reduction must be performed over the entire array. If a tuple of integers, logical OR reductions must be performed over multiple axes. A valid `axis` must be an integer on the interval `[-N, N)`, where `N` is the rank (number of dimensions) of `x`. If an `axis` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where `-1` refers to the last dimension). If provided an invalid `axis`, the function must raise an exception. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of `bool`. diff --git a/spec/API_specification/utility_functions.rst b/spec/API_specification/utility_functions.rst new file mode 100644 index 000000000..2a9f411bf --- /dev/null +++ b/spec/API_specification/utility_functions.rst @@ -0,0 +1,27 @@ +Utility Functions +================= + + Array API specification for utility functions. + +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`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. + +Objects in API +-------------- + +.. currentmodule:: signatures.utility_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + + all + any From fe93f2fbe672d7b45ac7b10478dfb0b44529412b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 20 Jan 2022 15:34:28 -0500 Subject: [PATCH 158/551] Fix notes and admonitions --- .../signatures/array_object.py | 448 ++++++++++-------- 1 file changed, 243 insertions(+), 205 deletions(-) diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 89bb72902..f726bd914 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -63,11 +63,12 @@ def shape() -> Tuple[Optional[int], ...]: out: Tuple[Optional[int], ...] array dimensions. An array dimension must be ``None`` if and only if a dimension is unknown. - Notes - ----- - - For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; ``A[:, B > 0]``) and thus cannot be statically resolved without knowing array contents. - - The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. + .. note:: + For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; ``A[:, B > 0]``) and thus cannot be statically resolved without knowing array contents. + + .. note:: + The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. """ @property @@ -75,16 +76,17 @@ def size() -> Optional[int]: """ Number of elements in an array. + .. note:: + This must equal the product of the array's dimensions. + Returns ------- out: Optional[int] number of elements in an array. The returned value must be ``None`` if and only if one or more array dimensions are unknown. - Notes - ----- - - This must equal the product of the array's dimensions. - - For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. + .. note:: + For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. """ @property @@ -99,30 +101,17 @@ def T() -> array: out: array two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array.two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. - Notes - ----- - - Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional ``permute_dims`` interface found in this specification. + + .. note:: + Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional ``permute_dims`` interface found in this specification. """ def __abs__(self: array, /) -> array: """ Calculates the absolute value for each element of an array instance (i.e., the element-wise result has the same magnitude as the respective element but has positive sign). - Parameters - ---------- - self: array - array instance. Should have a numeric data type. - - Returns - ------- - out: array - an array containing the element-wise absolute value. The returned array must have the same data type as ``self``. - - Notes - ----- - - For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. - - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-abs`. + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. **Special cases** @@ -131,29 +120,25 @@ def __abs__(self: array, /) -> array: - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``-0``, the result is ``+0``. - If ``x_i`` is ``-infinity``, the result is ``+infinity``. - """ - - def __add__(self: array, other: Union[int, float, array], /) -> array: - """ - Calculates the sum for each element of an array instance with the respective element of the array ``other``. Parameters ---------- self: array - array instance (augend array). Should have a numeric data type. - other: Union[int, float, array] - addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + array instance. Should have a numeric data type. Returns ------- out: array - an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + an array containing the element-wise absolute value. The returned array must have the same data type as ``self``. - Notes - ----- - - Floating-point addition is a commutative operation, but not always associative. - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-add`. + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-abs`. + """ + + def __add__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the sum for each element of an array instance with the respective element of the array ``other``. **Special cases** @@ -176,6 +161,25 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. + + .. note:: + Floating-point addition is a commutative operation, but not always associative. + + Parameters + ---------- + self: array + array instance (augend array). Should have a numeric data type. + other: Union[int, float, array] + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-add`. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -194,9 +198,9 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_and`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_and`. """ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: @@ -240,12 +244,39 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P self: array array instance. stream: Optional[Union[int, Any]] - for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be a positive integer or ``-1``. If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. - On CPU and other device types without streams, only ``None`` is accepted. + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be a positive integer or ``-1``. If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. + + For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + + + .. note:: + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + - For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for `stream` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + Device-specific notes: - **Tip** + + .. admonition:: CUDA + :class: note + + - ``None``: producer must assume the legacy default stream (default). + - ``1``: the legacy default stream. + - ``2``: the per-thread default stream. + - ``> 2``: stream number represented as a Python integer. + - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. + + + .. admonition:: ROCm + :class: note + + - ``None``: producer must assume the legacy default stream (default). + - ``0``: the default stream. + - ``> 2``: stream number represented as a Python integer. + - Using ``1`` and ``2`` is not supported. + + + .. admonition:: Tip + :class: important It is recommended that implementers explicitly handle streams. If they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` @@ -257,28 +288,6 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P ------- capsule: PyCapsule a DLPack capsule for the array. See :ref:`data-interchange` for details. - - Notes - ----- - - Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. - - Device-specific notes: - - **CUDA** - - - ``None``: producer must assume the legacy default stream (default). - - ``1``: the legacy default stream. - - ``2``: the per-thread default stream. - - ``> 2``: stream number represented as a Python integer. - - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. - - **ROCm** - - - ``None``: producer must assume the legacy default stream (default). - - ``0``: the default stream. - - ``> 2``: stream number represented as a Python integer. - - Using ``1`` and ``2`` is not supported. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -295,14 +304,16 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: device: Tuple[Enum, int] a tuple ``(device_type, device_id)`` in DLPack format. Valid device type enum members are: - - ``CPU = 1`` - - ``CUDA = 2`` - - ``CPU_PINNED = 3`` - - ``OPENCL = 4`` - - ``VULKAN = 7`` - - ``METAL = 8`` - - ``VPI = 9`` - - ``ROCM = 10`` + :: + + CPU = 1 + CUDA = 2 + CPU_PINNED = 3 + OPENCL = 4 + VULKAN = 7 + METAL = 8 + VPI = 9 + ROCM = 10 """ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -321,9 +332,9 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-equal`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-equal`. """ def __float__(self: array, /) -> float: @@ -345,25 +356,19 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: """ Evaluates ``self_i // other_i`` for each element of an array instance with the respective element of the array ``other``. - Parameters - ---------- - self: array - array instance. Should have a numeric data type. - other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - Returns - ------- - out: array - an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + **Special cases** - Notes - ----- - - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-floor_divide`. - - Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + .. note:: + Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. - **Special cases** + To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. + + Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. + + This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. @@ -389,6 +394,22 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to ``+infinity``) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-floor_divide`. """ def __ge__(self: array, other: Union[int, float, array], /) -> array: @@ -407,10 +428,10 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater_equal`. - """ + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater_equal`. + """ def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: """ @@ -445,15 +466,18 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater`. """ def __index__(self: array, /) -> int: """ Converts a zero-dimensional integer array to a Python ``int`` object. + .. note:: + This method is called to implement `operator.index() `_. See also `PEP 357 `_. + Parameters ---------- self: array @@ -463,10 +487,6 @@ def __index__(self: array, /) -> int: ------- out: int a Python ``int`` object representing the single element of the array instance. - - Notes - ----- - - This method is called to implement `operator.index() `_. See also `PEP 357 `_. """ def __int__(self: array, /) -> int: @@ -498,9 +518,9 @@ def __invert__(self: array, /) -> array: out: array an array containing the element-wise results. The returned array must have the same data type as `self`. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_invert`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_invert`. """ def __le__(self: array, other: Union[int, float, array], /) -> array: @@ -519,9 +539,9 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less_equal`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less_equal`. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -540,9 +560,9 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: out: array an array containing the element-wise results. The returned array must have the same data type as ``self``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_left_shift`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: @@ -561,15 +581,18 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less`. """ def __matmul__(self: array, other: array, /) -> array: """ Computes the matrix product. + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + Parameters ---------- self: array @@ -589,10 +612,9 @@ def __matmul__(self: array, other: array, /) -> array: - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. - The returned array must have a data type determined by :ref:`type-promotion`. - Notes - ----- - - The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). - - Results must equal the results returned by the equivalent function :ref:`function-matmul`. + + .. note:: + Results must equal the results returned by the equivalent function :ref:`function-matmul`. **Raises** @@ -607,6 +629,9 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: """ Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + Parameters ---------- self: array @@ -619,33 +644,15 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - Notes - ----- - - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-remainder`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-remainder`. """ def __mul__(self: array, other: Union[int, float, array], /) -> array: """ Calculates the product for each element of an array instance with the respective element of the array ``other``. - Parameters - ---------- - self: array - array instance. Should have a numeric data type. - other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. - - Returns - ------- - out: array - an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. - - Notes - ----- - - Floating-point multiplication is not always associative due to finite precision. - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-multiply`. - **Special cases** For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. @@ -659,6 +666,26 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. - In the remaining cases, where neither ``infinity`` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-multiply`. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -677,15 +704,18 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-not_equal`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-not_equal`. """ def __neg__(self: array, /) -> array: """ Evaluates ``-self_i`` for each element of an array instance. + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + Parameters ---------- self: array @@ -696,10 +726,9 @@ def __neg__(self: array, /) -> array: out: array an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. - Notes - ----- - - For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-negative`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-negative`. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -718,9 +747,9 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_or`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -737,32 +766,19 @@ def __pos__(self: array, /) -> array: out: array an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-positive`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-positive`. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: """ Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. - Parameters - ---------- - self: array - array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - other: Union[int, float, array] - other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + .. note:: + If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - Returns - ------- - out: array - an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. - - Notes - ----- - - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-pow`. + If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. **Special cases** @@ -792,6 +808,22 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + + Parameters + ---------- + self: array + array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + other: Union[int, float, array] + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-pow`. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -810,9 +842,9 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: out: array an array containing the element-wise results. The returned array must have the same data type as ``self``. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_right_shift`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_right_shift`. """ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: @@ -828,11 +860,14 @@ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, s value: Union[int, float, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). - Notes - ----- - - Setting array values must not affect the data type of ``self``. - - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). - - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + + .. note:: + + Setting array values must not affect the data type of ``self``. + + When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + + When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. """ def __sub__(self: array, other: Union[int, float, array], /) -> array: @@ -851,32 +886,19 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-subtract`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-subtract`. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: """ Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. - Parameters - ---------- - self: array - array instance. Should have a numeric data type. - other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. - - Returns - ------- - out: array - an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + .. note:: + If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-divide`. - - If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - - Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. **Special cases** @@ -904,6 +926,22 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-divide`. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: @@ -922,9 +960,9 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. - Notes - ----- - - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_xor`. + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_xor`. """ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: @@ -945,7 +983,7 @@ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any out: array an array with the same data and data type as ``self`` and located on the specified ``device``. - Notes - ----- - - If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. + + .. note:: + If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. """ From af981b9160545ddf1420c5eeb27843d3d14fa55c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 20 Jan 2022 18:26:36 -0500 Subject: [PATCH 159/551] Fix references and add missing __all__ --- spec/API_specification/signatures/array_object.py | 4 ++-- spec/API_specification/signatures/creation_functions.py | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index f726bd914..7a3c51322 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -237,7 +237,7 @@ def __bool__(self: array, /) -> bool: def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: """ - Exports the array for consumption by :ref:`function-from_dlpack` as a DLPack capsule. + Exports the array for consumption by :func:`signatures.creation_functions.from_dlpack` as a DLPack capsule. Parameters ---------- @@ -292,7 +292,7 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: """ - Returns device type and device ID in DLPack format. Meant for use within :ref:`function-from_dlpack`. + Returns device type and device ID in DLPack format. Meant for use within :func:`signatures.creation_functions.from_dlpack`. Parameters ---------- diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index 7ab6da3c4..77e9e32fa 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -368,3 +368,5 @@ def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d out: array an array having the same shape as ``x`` and filled with zeros. """ + +__all__ = ['arange', 'asarray', 'empty', 'empty_like', 'eye', 'from_dlpack', 'full', 'full_like', 'linspace', 'meshgrid', 'ones', 'ones_like', 'tril', 'triu', 'zeros', 'zeros_like'] From b9e95edefa562a5fe81d04520076a5204a7a4524 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Fri, 21 Jan 2022 12:26:59 -0500 Subject: [PATCH 160/551] Fix notes and admonitions --- .../signatures/creation_functions.py | 81 ++++++++++--------- 1 file changed, 45 insertions(+), 36 deletions(-) diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index 77e9e32fa..aa25a24a2 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -18,14 +18,14 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None device: Optional[device] device on which to place the created array. Default: ``None``. + + .. note:: + This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. + Returns ------- out: array a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. - - Notes - ----- - - This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. """ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: @@ -37,9 +37,11 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr obj: Union[array, bool, int, float, NestedSequence[bool | int | float], SupportsBufferProtocol] object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. - **Tip** + .. admonition:: Tip + :class: important + + An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. - An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. dtype: Optional[dtype] output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then @@ -48,6 +50,12 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr - if one or more values are ``float``\s, the output data type must be the default floating-point data type. Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :ref:`function-astype`. + device: Optional[device] device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. copy: Optional[bool] @@ -57,10 +65,6 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr ------- out: array an array containing the data from ``obj``. - - Notes - ----- - - If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :ref:`function-astype`. """ def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: @@ -138,9 +142,10 @@ def from_dlpack(x: object, /) -> array: out: array an array containing the data in `x`. - Notes - ----- - - The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + .. admonition:: Note + :class: note + + The returned array may be either a copy or a view. See :ref:`data-interchange` for details. """ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: @@ -155,6 +160,10 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d fill value. dtype: Optional[dtype] output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value``. If the fill value is an ``int``, the output array data type must be the default integer data type. If the fill value is a ``float``, the output array data type must be the default floating-point data type. If the fill value is a ``bool``, the output array must have boolean data type. Default: ``None``. + + .. note:: + If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + device: Optional[device] device on which to place the created array. Default: ``None``. @@ -162,10 +171,6 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d ------- out: array an array where every element is equal to ``fill_value``. - - Notes - ----- - - If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. """ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: @@ -180,6 +185,13 @@ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dty fill value. dtype: Optional[dtype] output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + + .. note:: + If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + + .. note:: + If ``dtype`` is ``None`` and the ``fill_value`` has a data type (``int`` or ``float``) which is not of the same data type kind as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + device: Optional[device] device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. @@ -187,11 +199,6 @@ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dty ------- out: array an array having the same shape as ``x`` and where every element is equal to ``fill_value``. - - Notes - ----- - - If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. - - If ``dtype`` is ``None`` and the ``fill_value`` has a data type (``int`` or ``float``) which is not of the same data type kind as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. """ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, dtype: Optional[dtype] = None, device: Optional[device] = None, endpoint: bool = True) -> array: @@ -204,6 +211,10 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, the start of the interval. stop: Union[int, float] the end of the interval. If ``endpoint`` is ``False``, the function must generate a sequence of ``num+1`` evenly spaced numbers starting with ``start`` and ending with ``stop`` and exclude the ``stop`` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval ``[start, stop)``. If ``endpoint`` is ``True``, the output array must consist of evenly spaced numbers over the closed interval ``[start, stop]``. Default: ``True``. + + .. note:: + The step size changes when `endpoint` is `False`. + num: int number of samples. Must be a non-negative integer value; otherwise, the function must raise an exception. dtype: Optional[dtype] @@ -217,10 +228,6 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, ------- out: array a one-dimensional array containing evenly spaced values. - - Notes - ----- - - The step size changes when `endpoint` is `False`. """ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: @@ -291,6 +298,9 @@ def tril(x: array, /, *, k: int = 0) -> array: """ Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. + .. note:: + The lower triangular part of the matrix is defined as the elements on and below the specified diagonal ``k``. + Parameters ---------- x: array @@ -298,21 +308,22 @@ def tril(x: array, /, *, k: int = 0) -> array: k: int diagonal above which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + Returns ------- out: array an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. - - Notes - ----- - - The lower triangular part of the matrix is defined as the elements on and below the specified diagonal ``k``. - - The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. """ def triu(x: array, /, *, k: int = 0) -> array: """ Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. + .. note:: + The upper triangular part of the matrix is defined as the elements on and above the specified diagonal ``k``. + Parameters ---------- x: array @@ -320,15 +331,13 @@ def triu(x: array, /, *, k: int = 0) -> array: k: int diagonal below which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + Returns ------- out: array an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. - - Notes - ----- - - The upper triangular part of the matrix is defined as the elements on and above the specified diagonal ``k``. - - The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. """ def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: From ba9e8ea869ba92b0fd0a40060bdfd88dfd8f8ab9 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 24 Jan 2022 05:29:42 -0500 Subject: [PATCH 161/551] Transform parallelism md to rst (#380) --- spec/design_topics/{parallelism.md => parallelism.rst} | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) rename spec/design_topics/{parallelism.md => parallelism.rst} (84%) diff --git a/spec/design_topics/parallelism.md b/spec/design_topics/parallelism.rst similarity index 84% rename from spec/design_topics/parallelism.md rename to spec/design_topics/parallelism.rst index 38ccb9343..77d06c966 100644 --- a/spec/design_topics/parallelism.md +++ b/spec/design_topics/parallelism.rst @@ -1,4 +1,5 @@ -# Parallelism +Parallelism +=========== Parallelism is mostly, but not completely, an execution or runtime concern rather than an API concern. Execution semantics are out of scope for this API @@ -7,7 +8,7 @@ involves how libraries allow users to exercise control over the parallelism they offer, such as: - Via environment variables. This is the method of choice for BLAS libraries and libraries using OpenMP. -- Via a keyword to individual functions or methods. Examples include the `n_jobs` keyword used in scikit-learn and the `workers` keyword used in SciPy. +- Via a keyword to individual functions or methods. Examples include the ``n_jobs`` keyword used in scikit-learn and the ``workers`` keyword used in SciPy. - Build-time settings to enable a parallel or distributed backend. - Via letting the user set chunk sizes. Dask uses this approach. @@ -19,5 +20,5 @@ coordination of parallelization behavior in a stack of Python libraries are: 2. A common library providing a parallelization layer Option (1) may possibly fit in a future version of this array API standard. -[array-api issue 4](https://github.com/data-apis/array-api/issues/4) contains +`array-api issue 4 `_ contains more detailed discussion on the topic of parallelism. \ No newline at end of file From bfbd2a85d8a74308e81f84437d01983938e3be7b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 24 Jan 2022 05:30:11 -0500 Subject: [PATCH 162/551] PR: Transform static typing md to rst (#381) * Transform static typing md to rst * fix warning --- .../{static_typing.md => static_typing.rst} | 48 ++++++++++--------- 1 file changed, 25 insertions(+), 23 deletions(-) rename spec/design_topics/{static_typing.md => static_typing.rst} (64%) diff --git a/spec/design_topics/static_typing.md b/spec/design_topics/static_typing.rst similarity index 64% rename from spec/design_topics/static_typing.md rename to spec/design_topics/static_typing.rst index cc744ca0f..26a1fb901 100644 --- a/spec/design_topics/static_typing.md +++ b/spec/design_topics/static_typing.rst @@ -1,43 +1,45 @@ -# Static typing +Static typing +============= Good support for static typing both in array libraries and array-consuming code is desirable. Therefore the exact type or set of types for each parameter, keyword and return value is specified for functions and methods - -see {ref}`function-and-method-signatures`. That section specifies arrays -simply as `array`; what that means is dealt with in this section. +see :ref:`function-and-method-signatures`. That section specifies arrays +simply as ``array``; what that means is dealt with in this section. Introducing type annotations in libraries became more relevant only when Python 2.7 support was dropped at the start of 2020. As a consequence, using type annotations with array libraries is largely still a work in progress. -This version of the API standard does not deal with trying to type _array -properties_ like shape, dimensionality or dtype, because that's not a solved +This version of the API standard does not deal with trying to type *array +properties* like shape, dimensionality or dtype, because that's not a solved problem in individual array libraries yet. -An `array` type annotation can mean either the type of one specific array +An ``array`` type annotation can mean either the type of one specific array object, or some superclass or typing Protocol - as long as it is consistent -with the array object specified in {ref}`array-object`. To illustrate by +with the array object specified in :ref:`array-object`. To illustrate by example: -```python -# `Array` is a particular class in the library -def sin(x: Array, / ...) -> Array: - ... -``` - -and - -```python -# There's some base class `_BaseArray`, and there may be multiple -# array subclasses inside the library -A = TypeVar('A', bound=_BaseArray) -def sin(x: A, / ...) -> A: - ... -``` +.. code-block:: python + + # `Array` is a particular class in the library + def sin(x: Array, / ...) -> Array: + ... + +and + +.. code-block:: python + + # There's some base class `_BaseArray`, and there may be multiple + # array subclasses inside the library + A = TypeVar('A', bound=_BaseArray) + def sin(x: A, / ...) -> A: + ... + should both be fine. There may be other variations possible. Also note that this standard does not require that input and output array types are the same (they're expected to be defined in the same library though). Given that array libraries don't have to be aware of other types of arrays defined in -other libraries (see {ref}`assumptions-dependencies`), this should be enough +other libraries (see :ref:`assumptions-dependencies`), this should be enough for a single array library. That said, an array-consuming library aiming to support multiple array types From e3bd0a1d4c563a124e87d373f25ac70e4729ac8b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 24 Jan 2022 05:36:19 -0500 Subject: [PATCH 163/551] Transform data interchange mechanisms md to rst (#378) --- spec/design_topics/data_interchange.md | 181 ----------------------- spec/design_topics/data_interchange.rst | 185 ++++++++++++++++++++++++ 2 files changed, 185 insertions(+), 181 deletions(-) delete mode 100644 spec/design_topics/data_interchange.md create mode 100644 spec/design_topics/data_interchange.rst diff --git a/spec/design_topics/data_interchange.md b/spec/design_topics/data_interchange.md deleted file mode 100644 index 5084c42f1..000000000 --- a/spec/design_topics/data_interchange.md +++ /dev/null @@ -1,181 +0,0 @@ -(data-interchange)= - -# Data interchange mechanisms - -This section discusses the mechanism to convert one type of array into another. -As discussed in the {ref}`assumptions-dependencies ` section, -_functions_ provided by an array library are not expected to operate on -_array types_ implemented by another library. Instead, the array can be -converted to a "native" array type. - -The interchange mechanism must offer the following: - -1. Data access via a protocol that describes the memory layout of the array - in an implementation-independent manner. - - _Rationale: any number of libraries must be able to exchange data, and no - particular package must be needed to do so._ - -2. Support for all dtypes in this API standard (see {ref}`data-types`). - -3. Device support. It must be possible to determine on what device the array - that is to be converted lives. - - _Rationale: there are CPU-only, GPU-only, and multi-device array types; - it's best to support these with a single protocol (with separate - per-device protocols it's hard to figure out unambiguous rules for which - protocol gets used, and the situation will get more complex over time - as TPU's and other accelerators become more widely available)._ - -4. Zero-copy semantics where possible, making a copy only if needed (e.g. - when data is not contiguous in memory). - - _Rationale: performance._ - -5. A Python-side and a C-side interface, the latter with a stable C ABI. - - _Rationale: all prominent existing array libraries are implemented in - C/C++, and are released independently from each other. Hence a stable C - ABI is required for packages to work well together._ - -The best candidate for this protocol is -[DLPack](https://github.com/dmlc/dlpack), and hence that is what this -standard has chosen as the primary/recommended protocol. Note that the -`asarray` function also supports the Python buffer protocol (CPU-only) to -support libraries that already implement buffer protocol support. - -```{note} - -The main alternatives to DLPack are device-specific methods: - -- The [buffer protocol](https://docs.python.org/dev/c-api/buffer.html) on CPU -- `__cuda_array_interface__` for CUDA, specified in the Numba documentation - [here](https://numba.pydata.org/numba-doc/0.43.0/cuda/cuda_array_interface.html) - (Python-side only at the moment) - -An issue with device-specific protocols are: if two libraries both -support multiple device types, in which order should the protocols be -tried? A growth in the number of protocols to support each time a new -device gets supported by array libraries (e.g. TPUs, AMD GPUs, emerging -hardware accelerators) also seems undesirable. - -In addition to the above argument, it is also clear from adoption -patterns that DLPack has the widest support. The buffer protocol, despite -being a lot older and standardized as part of Python itself via PEP 3118, -hardly has any support from array libraries. CPU interoperability is -mostly dealt with via the NumPy-specific `__array__` (which, when called, -means the object it is attached to must return a `numpy.ndarray` -containing the data the object holds). - -See the [RFC to adopt DLPack](https://github.com/data-apis/consortium-feedback/issues/1) -for discussion that preceded the adoption of DLPack. -``` - -## DLPack support - -:::{note} -DLPack is a standalone protocol/project and can therefore be used outside of -this standard. Python libraries that want to implement only DLPack support -are recommended to do so using the same syntax and semantics as outlined -below. They are not required to return an array object from `from_dlpack` -which conforms to this standard. - -DLPack itself has no documentation currently outside of the inline comments in -[dlpack.h](https://github.com/dmlc/dlpack/blob/main/include/dlpack/dlpack.h). -In the future, the below content may be migrated to the (to-be-written) DLPack docs. -::: - -### Syntax for data interchange with DLPack - -The array API will offer the following syntax for data interchange: - -1. A `from_dlpack(x)` function, which accepts (array) objects with a - `__dlpack__` method and uses that method to construct a new array - containing the data from `x`. -2. `__dlpack__(self, stream=None)` and `__dlpack_device__` methods on the - array object, which will be called from within `from_dlpack`, to query - what device the array is on (may be needed to pass in the correct - stream, e.g. in the case of multiple GPUs) and to access the data. - - -### Semantics - -DLPack describe the memory layout of strided, n-dimensional arrays. -When a user calls `y = from_dlpack(x)`, the library implementing `x` (the -"producer") will provide access to the data from `x` to the library -containing `from_dlpack` (the "consumer"). If possible, this must be -zero-copy (i.e. `y` will be a _view_ on `x`). If not possible, that library -may make a copy of the data. In both cases: -- the producer keeps owning the memory -- `y` may or may not be a view, therefore the user must keep the - recommendation to avoid mutating `y` in mind - see - {ref}`copyview-mutability`. -- Both `x` and `y` may continue to be used just like arrays created in other ways. - -If an array that is accessed via the interchange protocol lives on a -device that the requesting library does not support, it is recommended to -raise a `TypeError`. - -Stream handling through the `stream` keyword applies to CUDA and ROCm (perhaps -to other devices that have a stream concept as well, however those haven't been -considered in detail). The consumer must pass the stream it will use to the -producer; the producer must synchronize or wait on the stream when necessary. -In the common case of the default stream being used, synchronization will be -unnecessary so asynchronous execution is enabled. - - -### Implementation - -_Note that while this API standard largely tries to avoid discussing -implementation details, some discussion and requirements are needed -here because data interchange requires coordination between -implementers on, e.g., memory management._ - -![Diagram of DLPack structs](/_static/images/DLPack_diagram.png) - -_DLPack diagram. Dark blue are the structs it defines, light blue -struct members, gray text enum values of supported devices and data -types._ - -The `__dlpack__` method will produce a `PyCapsule` containing a -`DLManagedTensor`, which will be consumed immediately within -`from_dlpack` - therefore it is consumed exactly once, and it will not be -visible to users of the Python API. - -The producer must set the `PyCapsule` name to ``"dltensor"`` so that -it can be inspected by name, and set `PyCapsule_Destructor` that calls -the `deleter` of the `DLManagedTensor` when the `"dltensor"`-named -capsule is no longer needed. - -The consumer must transer ownership of the `DLManangedTensor` from the -capsule to its own object. It does so by renaming the capsule to -`"used_dltensor"` to ensure that `PyCapsule_Destructor` will not get -called (ensured if `PyCapsule_Destructor` calls `deleter` only for -capsules whose name is `"dltensor"`), but the `deleter` of the -`DLManagedTensor` will be called by the destructor of the consumer -library object created to own the `DLManagerTensor` obtained from the -capsule. - -Note: the capsule names ``"dltensor"`` and `"used_dltensor"` must be -statically allocated. - -When the `strides` field in the `DLTensor` struct is `NULL`, it indicates a -row-major compact array. If the array is of size zero, the data pointer in -`DLTensor` should be set to either `NULL` or `0`. - -DLPack version used must be `0.2 <= DLPACK_VERSION < 1.0`. For further -details on DLPack design and how to implement support for it, -refer to [github.com/dmlc/dlpack](https://github.com/dmlc/dlpack). - -:::{warning} DLPack contains a `device_id`, which will be the device -ID (an integer, `0, 1, ...`) which the producer library uses. In -practice this will likely be the same numbering as that of the -consumer, however that is not guaranteed. Depending on the hardware -type, it may be possible for the consumer library implementation to -look up the actual device from the pointer to the data - this is -possible for example for CUDA device pointers. - -It is recommended that implementers of this array API consider and document -whether the `.device` attribute of the array returned from `from_dlpack` is -guaranteed to be in a certain order or not. -::: diff --git a/spec/design_topics/data_interchange.rst b/spec/design_topics/data_interchange.rst new file mode 100644 index 000000000..d8ab07f42 --- /dev/null +++ b/spec/design_topics/data_interchange.rst @@ -0,0 +1,185 @@ +.. _data-interchange: + +Data interchange mechanisms +=========================== + +This section discusses the mechanism to convert one type of array into another. +As discussed in the :ref:`assumptions-dependencies ` section, +*functions* provided by an array library are not expected to operate on +*array types* implemented by another library. Instead, the array can be +converted to a "native" array type. + +The interchange mechanism must offer the following: + +1. Data access via a protocol that describes the memory layout of the array + in an implementation-independent manner. + + *Rationale: any number of libraries must be able to exchange data, and no + particular package must be needed to do so.* + +2. Support for all dtypes in this API standard (see :ref:`data-types`). + +3. Device support. It must be possible to determine on what device the array + that is to be converted lives. + + *Rationale: there are CPU-only, GPU-only, and multi-device array types; + it's best to support these with a single protocol (with separate + per-device protocols it's hard to figure out unambiguous rules for which + protocol gets used, and the situation will get more complex over time + as TPU's and other accelerators become more widely available).* + +4. Zero-copy semantics where possible, making a copy only if needed (e.g. + when data is not contiguous in memory). + + *Rationale: performance.* + +5. A Python-side and a C-side interface, the latter with a stable C ABI. + + *Rationale: all prominent existing array libraries are implemented in + C/C++, and are released independently from each other. Hence a stable C + ABI is required for packages to work well together.* + +The best candidate for this protocol is +`DLPack `_, and hence that is what this +standard has chosen as the primary/recommended protocol. Note that the +``asarray`` function also supports the Python buffer protocol (CPU-only) to +support libraries that already implement buffer protocol support. + +.. note:: + The main alternatives to DLPack are device-specific methods: + + - The `buffer protocol `_ on CPU + - ``__cuda_array_interface__`` for CUDA, specified in the Numba documentation + `here `_ + (Python-side only at the moment) + + An issue with device-specific protocols are: if two libraries both + support multiple device types, in which order should the protocols be + tried? A growth in the number of protocols to support each time a new + device gets supported by array libraries (e.g. TPUs, AMD GPUs, emerging + hardware accelerators) also seems undesirable. + + In addition to the above argument, it is also clear from adoption + patterns that DLPack has the widest support. The buffer protocol, despite + being a lot older and standardized as part of Python itself via PEP 3118, + hardly has any support from array libraries. CPU interoperability is + mostly dealt with via the NumPy-specific ``__array__`` (which, when called, + means the object it is attached to must return a ``numpy.ndarray`` + containing the data the object holds). + + See the `RFC to adopt DLPack `_ + for discussion that preceded the adoption of DLPack. + + +DLPack support +-------------- + +.. note:: + DLPack is a standalone protocol/project and can therefore be used outside of + this standard. Python libraries that want to implement only DLPack support + are recommended to do so using the same syntax and semantics as outlined + below. They are not required to return an array object from ``from_dlpack`` + which conforms to this standard. + + DLPack itself has no documentation currently outside of the inline comments in + `dlpack.h `_. + In the future, the below content may be migrated to the (to-be-written) DLPack docs. + + +Syntax for data interchange with DLPack +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The array API will offer the following syntax for data interchange: + +1. A ``from_dlpack(x)`` function, which accepts (array) objects with a + ``__dlpack__`` method and uses that method to construct a new array + containing the data from ``x``. +2. ``__dlpack__(self, stream=None)`` and ``__dlpack_device__`` methods on the + array object, which will be called from within ``from_dlpack``, to query + what device the array is on (may be needed to pass in the correct + stream, e.g. in the case of multiple GPUs) and to access the data. + + +Semantics +~~~~~~~~~ + +DLPack describe the memory layout of strided, n-dimensional arrays. +When a user calls ``y = from_dlpack(x)``, the library implementing ``x`` (the +"producer") will provide access to the data from ``x`` to the library +containing ``from_dlpack`` (the "consumer"). If possible, this must be +zero-copy (i.e. ``y`` will be a *view* on ``x``). If not possible, that library +may make a copy of the data. In both cases: + +- the producer keeps owning the memory +- ``y`` may or may not be a view, therefore the user must keep the recommendation to avoid mutating ``y`` in mind - see :ref:`copyview-mutability`. +- Both ``x`` and ``y`` may continue to be used just like arrays created in other ways. + +If an array that is accessed via the interchange protocol lives on a +device that the requesting library does not support, it is recommended to +raise a ``TypeError``. + +Stream handling through the ``stream`` keyword applies to CUDA and ROCm (perhaps +to other devices that have a stream concept as well, however those haven't been +considered in detail). The consumer must pass the stream it will use to the +producer; the producer must synchronize or wait on the stream when necessary. +In the common case of the default stream being used, synchronization will be +unnecessary so asynchronous execution is enabled. + + +Implementation +~~~~~~~~~~~~~~ + +*Note that while this API standard largely tries to avoid discussing +implementation details, some discussion and requirements are needed +here because data interchange requires coordination between +implementers on, e.g., memory management.* + +.. image:: /_static/images/DLPack_diagram.png + :alt: Diagram of DLPack structs + +*DLPack diagram. Dark blue are the structs it defines, light blue +struct members, gray text enum values of supported devices and data +types.* + +The ``__dlpack__`` method will produce a ``PyCapsule`` containing a +``DLManagedTensor``, which will be consumed immediately within +``from_dlpack`` - therefore it is consumed exactly once, and it will not be +visible to users of the Python API. + +The producer must set the ``PyCapsule`` name to ``"dltensor"`` so that +it can be inspected by name, and set ``PyCapsule_Destructor`` that calls +the ``deleter`` of the ``DLManagedTensor`` when the ``"dltensor"``-named +capsule is no longer needed. + +The consumer must transer ownership of the ``DLManangedTensor`` from the +capsule to its own object. It does so by renaming the capsule to +``"used_dltensor"`` to ensure that ``PyCapsule_Destructor`` will not get +called (ensured if ``PyCapsule_Destructor`` calls ``deleter`` only for +capsules whose name is ``"dltensor"``), but the ``deleter`` of the +``DLManagedTensor`` will be called by the destructor of the consumer +library object created to own the ``DLManagerTensor`` obtained from the +capsule. + +Note: the capsule names ``"dltensor"`` and ``"used_dltensor"`` must be +statically allocated. + +When the ``strides`` field in the ``DLTensor`` struct is ``NULL``, it indicates a +row-major compact array. If the array is of size zero, the data pointer in +``DLTensor`` should be set to either ``NULL`` or ``0``. + +DLPack version used must be ``0.2 <= DLPACK_VERSION < 1.0``. For further +details on DLPack design and how to implement support for it, +refer to `github.com/dmlc/dlpack `_. + +.. warning:: + DLPack contains a ``device_id``, which will be the device + ID (an integer, ``0, 1, ...``) which the producer library uses. In + practice this will likely be the same numbering as that of the + consumer, however that is not guaranteed. Depending on the hardware + type, it may be possible for the consumer library implementation to + look up the actual device from the pointer to the data - this is + possible for example for CUDA device pointers. + + It is recommended that implementers of this array API consider and document + whether the ``.device`` attribute of the array returned from ``from_dlpack`` is + guaranteed to be in a certain order or not. From ce1b5a3e836316e49b2fb522d3db72ae6bd68b04 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 24 Jan 2022 05:38:29 -0500 Subject: [PATCH 164/551] Transform C API md to rst (#374) --- spec/design_topics/C_API.md | 93 ----------------------------------- spec/design_topics/C_API.rst | 94 ++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 93 deletions(-) delete mode 100644 spec/design_topics/C_API.md create mode 100644 spec/design_topics/C_API.rst diff --git a/spec/design_topics/C_API.md b/spec/design_topics/C_API.md deleted file mode 100644 index 96575ba63..000000000 --- a/spec/design_topics/C_API.md +++ /dev/null @@ -1,93 +0,0 @@ -(C-API)= - -# C API - -Use of a C API is out of scope for this array API, as mentioned in {ref}`Scope`. -There are a lot of libraries that do use such an API - in particular via Cython code -or via direct usage of the NumPy C API. When the maintainers of such libraries -want to use this array API standard to support multiple types of arrays, they -need a way to deal with that issue. This section aims to provide some guidance. - -The assumption in the rest of this section is that performance matters for the library, -and hence the goal is to make other array types work without converting to a -`numpy.ndarray` or another particular array type. If that's not the case (e.g. for a -visualization package), then other array types can simply be handled by converting -to the supported array type. - -```{note} - -Often a zero-copy conversion to `numpy.ndarray` is possible, at least for CPU arrays. -If that's the case, this may be a good way to support other array types. -The main difficulty in that case will be getting the return array type right - however, -this standard does provide a Python-level API for array construction that should allow -doing this. A relevant question is if it's possible to know with -certainty that a conversion will be zero-copy. This may indeed be -possible, see {ref}`data-interchange`. -``` - -## Example situations for C/Cython usage - -### Situation 1: a Python package that is mostly pure Python, with a limited number of Cython extensions - -```{note} - -Projects in this situation include Statsmodels, scikit-bio and QuTiP -``` - -Main strategy: documentation. The functionality using Cython code will not support other array types (or only with conversion to/from `numpy.ndarray`), which can be documented per function. - - -### Situation 2: a Python package that contains a lot of Cython code - -```{note} - -Projects in this situation include scikit-learn and scikit-image -``` - -Main strategy: add support for other array types _per submodule_. This keeps it manageable to explain to the user which functionality does and doesn't have support. - -Longer term: specific support for particular array types (e.g. `cupy.ndarray` can be supported with Python-only code via `cupy.ElementwiseKernel`). - - -### Situation 3: a Python package that uses the NumPy or Python C API directly - -```{note} - -Projects in this situation include SciPy and Astropy -``` - -Strategy: similar to _situation 2_, but the number of submodules that can support all array types may be limited. - - -## Device support - -Supporting non-CPU array types in code using the C API or Cython seems problematic, -this almost inevitably will require custom device-specific code (e.g., CUDA, ROCm) or -something like JIT compilation with Numba. - - -## Other longer-term approaches - -### Further Python API standardization - -There may be cases where it makes sense to standardize additional sets of -functions, because they're important enough that array libraries tend to -reimplement them. An example of this may be _special functions_, as provided -by `scipy.special`. Bessel and gamma functions for example are commonly -reimplemented by array libraries. This may avoid having to drop into a -particular implementation that does use a C API (e.g., one can then rely on -`arraylib.special.gamma` rather than having to use `scipy.special.gamma`). - - -### HPy - -[HPy](https://github.com/hpyproject/hpy) is a new project that will provide a higher-level -C API and ABI than CPython offers. A Cython backend targeting HPy will be provided as well. - -- Better PyPy support -- Universal ABI - single binary for all supported Python versions -- Cython backend generating HPy rather than CPython code - -HPy isn't quite ready for mainstream usage today, but once it does it may -help make supporting multiple array libraries or adding non-CPU device -support to Cython more feasible. diff --git a/spec/design_topics/C_API.rst b/spec/design_topics/C_API.rst new file mode 100644 index 000000000..ec2b721f8 --- /dev/null +++ b/spec/design_topics/C_API.rst @@ -0,0 +1,94 @@ +.. _C-API: + +C API +===== + +Use of a C API is out of scope for this array API, as mentioned in :ref:`Scope`. +There are a lot of libraries that do use such an API - in particular via Cython code +or via direct usage of the NumPy C API. When the maintainers of such libraries +want to use this array API standard to support multiple types of arrays, they +need a way to deal with that issue. This section aims to provide some guidance. + +The assumption in the rest of this section is that performance matters for the library, +and hence the goal is to make other array types work without converting to a +``numpy.ndarray`` or another particular array type. If that's not the case (e.g. for a +visualization package), then other array types can simply be handled by converting +to the supported array type. + +.. note:: + Often a zero-copy conversion to ``numpy.ndarray`` is possible, at least for CPU arrays. + If that's the case, this may be a good way to support other array types. + The main difficulty in that case will be getting the return array type right - however, + this standard does provide a Python-level API for array construction that should allow + doing this. A relevant question is if it's possible to know with + certainty that a conversion will be zero-copy. This may indeed be + possible, see :ref:`data-interchange`. + + +Example situations for C/Cython usage +------------------------------------- + +Situation 1: a Python package that is mostly pure Python, with a limited number of Cython extensions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include Statsmodels, scikit-bio and QuTiP + +Main strategy: documentation. The functionality using Cython code will not support other array types (or only with conversion to/from ``numpy.ndarray``), which can be documented per function. + + +Situation 2: a Python package that contains a lot of Cython code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include scikit-learn and scikit-image + +Main strategy: add support for other array types *per submodule*. This keeps it manageable to explain to the user which functionality does and doesn't have support. + +Longer term: specific support for particular array types (e.g. ``cupy.ndarray`` can be supported with Python-only code via ``cupy.ElementwiseKernel``). + + +Situation 3: a Python package that uses the NumPy or Python C API directly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include SciPy and Astropy + +Strategy: similar to *situation 2*, but the number of submodules that can support all array types may be limited. + + +Device support +-------------- + +Supporting non-CPU array types in code using the C API or Cython seems problematic, +this almost inevitably will require custom device-specific code (e.g., CUDA, ROCm) or +something like JIT compilation with Numba. + + +Other longer-term approaches +---------------------------- + +Further Python API standardization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There may be cases where it makes sense to standardize additional sets of +functions, because they're important enough that array libraries tend to +reimplement them. An example of this may be *special functions*, as provided +by ``scipy.special``. Bessel and gamma functions for example are commonly +reimplemented by array libraries. This may avoid having to drop into a +particular implementation that does use a C API (e.g., one can then rely on +``arraylib.special.gamma`` rather than having to use ``scipy.special.gamma``). + +HPy +~~~ + +`HPy `_ is a new project that will provide a higher-level +C API and ABI than CPython offers. A Cython backend targeting HPy will be provided as well. + +- Better PyPy support +- Universal ABI - single binary for all supported Python versions +- Cython backend generating HPy rather than CPython code + +HPy isn't quite ready for mainstream usage today, but once it does it may +help make supporting multiple array libraries or adding non-CPU device +support to Cython more feasible. From 1bd80440e0d8aa93a5975f96ce18e53c85c3098f Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 24 Jan 2022 05:40:26 -0500 Subject: [PATCH 165/551] Transform data dependent output shapes md to rst (#377) --- ...ut_shapes.md => data_dependent_output_shapes.rst} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename spec/design_topics/{data_dependent_output_shapes.md => data_dependent_output_shapes.rst} (63%) diff --git a/spec/design_topics/data_dependent_output_shapes.md b/spec/design_topics/data_dependent_output_shapes.rst similarity index 63% rename from spec/design_topics/data_dependent_output_shapes.md rename to spec/design_topics/data_dependent_output_shapes.rst index d8347520d..43daa9765 100644 --- a/spec/design_topics/data_dependent_output_shapes.md +++ b/spec/design_topics/data_dependent_output_shapes.rst @@ -1,6 +1,7 @@ -(data-dependent-output-shapes)= +.. _data-dependent-output-shapes: -# Data-dependent output shapes +Data-dependent output shapes +============================ Array libraries which build computation graphs commonly employ static analysis that relies upon known shapes. For example, JAX requires known array sizes when compiling code, in order to perform static memory allocation. Functions and operations which are value-dependent present difficulties for such libraries, as array sizes cannot be inferred ahead of time without also knowing the contents of the respective arrays. @@ -8,8 +9,7 @@ While value-dependent functions and operations are not impossible to implement f Value-dependent operations are demarcated in this specification using an admonition similar to the following: -:::{admonition} Data-dependent output shape -:class: important +.. admonition:: Data-dependent output shape + :class: important -The shape of the output array for this function/operation depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function/operation difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. -::: + The shape of the output array for this function/operation depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function/operation difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. From d4b7e9a4f46bc5723e7afce176f1a2df0362a13b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 24 Jan 2022 05:42:31 -0500 Subject: [PATCH 166/551] Transform accuracy md to rst (#375) --- spec/design_topics/accuracy.md | 78 --------------------------------- spec/design_topics/accuracy.rst | 77 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 78 deletions(-) delete mode 100644 spec/design_topics/accuracy.md create mode 100644 spec/design_topics/accuracy.rst diff --git a/spec/design_topics/accuracy.md b/spec/design_topics/accuracy.md deleted file mode 100644 index 1ef6005d0..000000000 --- a/spec/design_topics/accuracy.md +++ /dev/null @@ -1,78 +0,0 @@ -(accuracy)= - -# Accuracy - -> Array API specification for minimum accuracy requirements. - -## Arithmetic Operations - -The results of element-wise arithmetic operations - -- `+` -- `-` -- `*` -- `/` -- `%` - -including the corresponding element-wise array APIs defined in this standard - -- add -- subtract -- multiply -- divide - -for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be `roundTiesToEven` (i.e., ties rounded toward the nearest value with an even least significant bit). - -## Mathematical Functions - -This specification does **not** precisely define the behavior of the following functions - -- acos -- acosh -- asin -- asinh -- atan -- atan2 -- atanh -- cos -- cosh -- exp -- expm1 -- log -- log1p -- log2 -- log10 -- pow -- sin -- sinh -- tan -- tanh - -except to require specific results for certain argument values that represent boundary cases of interest. - -```{note} - -To help readers identify functions lacking precisely defined accuracy behavior, this specification uses the phrase "implementation-dependent approximation" in function descriptions. -``` - -For other argument values, these functions should compute approximations to the results of respective mathematical functions; however, this specification recognizes that array libraries may be constrained by underlying hardware and/or seek to optimize performance over absolute accuracy and, thus, allows some latitude in the choice of approximation algorithms. - -Although the specification leaves the choice of algorithms to the implementation, this specification recommends (but does not specify) that implementations use the approximation algorithms for IEEE 754-2019 arithmetic contained in [FDLIBM](http://www.netlib.org/fdlibm), the freely distributable mathematical library from Sun Microsystems, or some other comparable IEEE 754-2019 compliant mathematical library. - -```{note} - -With exception of a few mathematical functions, returning results which are indistinguishable from correctly rounded infinitely precise results is difficult, if not impossible, to achieve due to the algorithms involved, the limits of finite-precision, and error propagation. However, this specification recognizes that numerical accuracy alignment among array libraries is desirable in order to ensure portability and reproducibility. Accordingly, for each mathematical function, the specification test suite includes test values which span a function's domain and reports the average and maximum deviation from either a designated standard implementation (e.g., an arbitrary precision arithmetic implementation) or an average computed across a subset of known array library implementations. Such reporting aids users who need to know how accuracy varies among libraries and developers who need to check the validity of their implementations. -``` - -## Statistical Functions - -This specification does not specify accuracy requirements for statistical functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. - -```{note} - -In order for an array library to pass the specification test suite, an array library's statistical function implementations must satisfy certain bare-minimum accuracy requirements (e.g., accurate summation of a small set of positive integers). Unfortunately, imposing more rigorous accuracy requirements is not possible without severely curtailing possible implementation algorithms and unduly increasing implementation complexity. -``` - -## Linear Algebra - -This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file diff --git a/spec/design_topics/accuracy.rst b/spec/design_topics/accuracy.rst new file mode 100644 index 000000000..df417d546 --- /dev/null +++ b/spec/design_topics/accuracy.rst @@ -0,0 +1,77 @@ +.. _accuracy: + +Accuracy +======== + + Array API specification for minimum accuracy requirements. + +Arithmetic Operations +--------------------- + +The results of element-wise arithmetic operations + +- ``+`` +- ``-`` +- ``*`` +- ``/`` +- ``%`` + +including the corresponding element-wise array APIs defined in this standard + +- add +- subtract +- multiply +- divide + +for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., ties rounded toward the nearest value with an even least significant bit). + +Mathematical Functions +---------------------- + +This specification does **not** precisely define the behavior of the following functions + +- acos +- acosh +- asin +- asinh +- atan +- atan2 +- atanh +- cos +- cosh +- exp +- expm1 +- log +- log1p +- log2 +- log10 +- pow +- sin +- sinh +- tan +- tanh + +except to require specific results for certain argument values that represent boundary cases of interest. + +.. note:: + To help readers identify functions lacking precisely defined accuracy behavior, this specification uses the phrase "implementation-dependent approximation" in function descriptions. + +For other argument values, these functions should compute approximations to the results of respective mathematical functions; however, this specification recognizes that array libraries may be constrained by underlying hardware and/or seek to optimize performance over absolute accuracy and, thus, allows some latitude in the choice of approximation algorithms. + +Although the specification leaves the choice of algorithms to the implementation, this specification recommends (but does not specify) that implementations use the approximation algorithms for IEEE 754-2019 arithmetic contained in `FDLIBM `_, the freely distributable mathematical library from Sun Microsystems, or some other comparable IEEE 754-2019 compliant mathematical library. + +.. note:: + With exception of a few mathematical functions, returning results which are indistinguishable from correctly rounded infinitely precise results is difficult, if not impossible, to achieve due to the algorithms involved, the limits of finite-precision, and error propagation. However, this specification recognizes that numerical accuracy alignment among array libraries is desirable in order to ensure portability and reproducibility. Accordingly, for each mathematical function, the specification test suite includes test values which span a function's domain and reports the average and maximum deviation from either a designated standard implementation (e.g., an arbitrary precision arithmetic implementation) or an average computed across a subset of known array library implementations. Such reporting aids users who need to know how accuracy varies among libraries and developers who need to check the validity of their implementations. + +Statistical Functions +--------------------- + +This specification does not specify accuracy requirements for statistical functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +.. note:: + In order for an array library to pass the specification test suite, an array library's statistical function implementations must satisfy certain bare-minimum accuracy requirements (e.g., accurate summation of a small set of positive integers). Unfortunately, imposing more rigorous accuracy requirements is not possible without severely curtailing possible implementation algorithms and unduly increasing implementation complexity. + +Linear Algebra +-------------- + +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file From b982b986fa4cfad2ff52b8cea09b4d20a5d36b73 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 24 Jan 2022 05:44:21 -0500 Subject: [PATCH 167/551] Transform copies & mutability md to rst (#376) --- ...ation.md => copies_views_and_mutation.rst} | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) rename spec/design_topics/{copies_views_and_mutation.md => copies_views_and_mutation.rst} (68%) diff --git a/spec/design_topics/copies_views_and_mutation.md b/spec/design_topics/copies_views_and_mutation.rst similarity index 68% rename from spec/design_topics/copies_views_and_mutation.md rename to spec/design_topics/copies_views_and_mutation.rst index 1911718b7..2ed3d8e41 100644 --- a/spec/design_topics/copies_views_and_mutation.md +++ b/spec/design_topics/copies_views_and_mutation.rst @@ -1,24 +1,25 @@ -(copyview-mutability)= +.. _copyview-mutability: -# Copy-view behaviour and mutability +Copy-view behaviour and mutability +================================== Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically have the concept of a "view", meaning an array containing data in memory that belongs to another array (i.e. a different "view" on the original data). Views are useful for performance reasons - not copying data to a new location saves memory and is faster than copying - but can also affect the semantics -of code. This happens when views are combined with _mutating_ operations. +of code. This happens when views are combined with *mutating* operations. This simple example illustrates that: -```python -x = ones(1) -y = x[:] # `y` *may* be a view on the data of `x` -y -= 1 # if `y` is a view, this modifies `x` -``` +.. code-block:: python + + x = ones(1) + y = x[:] # `y` *may* be a view on the data of `x` + y -= 1 # if `y` is a view, this modifies `x` Code as simple as the above example will not be portable between array -libraries - for NumPy/PyTorch/CuPy/MXNet `x` will contain the value `0`, -while for TensorFlow/JAX/Dask it will contain the value `1`. The combination +libraries - for NumPy/PyTorch/CuPy/MXNet ``x`` will contain the value ``0``, +while for TensorFlow/JAX/Dask it will contain the value ``1``. The combination of views and mutability is fundamentally problematic here if the goal is to be able to write code with unambiguous semantics. @@ -30,14 +31,14 @@ specify this - libraries can do either. There are several types of operations that do in-place mutation of data contained in arrays. These include: -1. Inplace operators (e.g. `*=`) -2. Item assignment (e.g. `x[0] = 1`) -3. Slice assignment (e.g., `x[:2, :] = 3`) -4. The `out=` keyword present in some strided array libraries (e.g. `sin(x, out=y`)) +1. Inplace operators (e.g. ``*=``) +2. Item assignment (e.g. ``x[0] = 1``) +3. Slice assignment (e.g., ``x[:2, :] = 3``) +4. The `out=` keyword present in some strided array libraries (e.g. ``sin(x, out=y)``) Libraries like TensorFlow and JAX tend to support inplace operators, provide -alternative syntax for item and slice assignment (e.g. an `update_index` -function or `x.at[idx].set(y)`), and have no need for `out=`. +alternative syntax for item and slice assignment (e.g. an ``update_index`` +function or ``x.at[idx].set(y)``), and have no need for ``out=``. A potential solution could be to make views read-only, or use copy-on-write semantics. Both are hard to implement and would present significant issues @@ -47,30 +48,28 @@ views would also not be a full solution, given that mutating the original does not attempt to go down this route. Both inplace operators and item/slice assignment can be mapped onto -equivalent functional expressions (e.g. `x[idx] = val` maps to -`x.at[idx].set(val)`), and given that both inplace operators and item/slice +equivalent functional expressions (e.g. ``x[idx] = val`` maps to +``x.at[idx].set(val)``), and given that both inplace operators and item/slice assignment are very widely used in both library and end user code, this standard chooses to include them. -The situation with `out=` is slightly different - it's less heavily used, and +The situation with ``out=`` is slightly different - it's less heavily used, and easier to avoid. It's also not an optimal API, because it mixes an "efficiency of implementation" consideration ("you're allowed to do this inplace") with the semantics of a function ("the output _must_ be placed into this array). There are libraries that do some form of tracing or abstract interpretation over a language that does not support mutation (to make -analysis easier); in those cases implementing `out=` with correct handling of +analysis easier); in those cases implementing ``out=`` with correct handling of views may even be impossible to do. There's alternatives, for example the donated arguments in JAX or working buffers in LAPACK, that allow the user to express "you _may_ overwrite this data, do whatever is fastest". Given that those alternatives aren't widely used in array libraries today, this API -standard chooses to (a) leave out `out=`, and (b) not specify another method +standard chooses to (a) leave out ``out=``, and (b) not specify another method of reusing arrays that are no longer needed as buffers. This leaves the problem of the initial example - with this API standard it remains possible to write code that will not work the same for all array libraries. This is something that the user must be careful about. -```{note} - -It is recommended that users avoid any mutating operations when a view may be involved. -``` +.. note:: + It is recommended that users avoid any mutating operations when a view may be involved. From fb6b57658e797fbe51c9e33f26f88e35a39d4152 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 25 Jan 2022 15:05:04 -0500 Subject: [PATCH 168/551] Update note directives --- .../signatures/linear_algebra_functions.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/spec/API_specification/signatures/linear_algebra_functions.py index 1fe4e65ec..a7608b9ad 100644 --- a/spec/API_specification/signatures/linear_algebra_functions.py +++ b/spec/API_specification/signatures/linear_algebra_functions.py @@ -5,6 +5,9 @@ def matmul(x1: array, x2: array, /) -> array: """ Computes the matrix product. + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + Parameters ---------- x1: array @@ -25,9 +28,6 @@ def matmul(x1: array, x2: array, /) -> array: The returned array must have a data type determined by :ref:`type-promotion`. - Notes - ----- - - The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). **Raises** @@ -63,6 +63,10 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], first input array. Should have a numeric data type. x2: array second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). Should have a numeric data type. + + .. note:: + Contracted axes (dimensions) must not be broadcasted. + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] number of axes (dimensions) to contract or explicit sequences of axes (dimensions) for ``x1`` and ``x2``, respectively. @@ -78,10 +82,6 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], ------- out: array an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. - - Notes - ----- - - Contracted axes (dimensions) must not be broadcasted. """ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: From ec9a7b3c790aec0196e2cfacc3358179dc85d610 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 26 Jan 2022 22:02:54 -0500 Subject: [PATCH 169/551] Fix non existing labels --- spec/API_specification/signatures/array_object.py | 2 +- spec/extensions/linear_algebra_functions.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 7a3c51322..87a055366 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -614,7 +614,7 @@ def __matmul__(self: array, other: array, /) -> array: .. note:: - Results must equal the results returned by the equivalent function :ref:`function-matmul`. + Results must equal the results returned by the equivalent function :func:`signatures.linear_algebra_functions.matmul`. **Raises** diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md index 6bdcdbd78..3d26436cc 100644 --- a/spec/extensions/linear_algebra_functions.md +++ b/spec/extensions/linear_algebra_functions.md @@ -258,7 +258,7 @@ Returns the multiplicative inverse of a square matrix (or a stack of square matr (function-linalg-matmul)= ### linalg.matmul(x1, x2, /) -Alias for {ref}`function-matmul`. +Alias for {func}`signatures.linear_algebra_functions.matmul`. (function-linalg-matrix-norm)= ### linalg.matrix_norm(x, /, *, keepdims=False, ord='fro') @@ -352,7 +352,7 @@ Returns the rank (i.e., number of non-zero singular values) of a matrix (or a st (function-linalg-matrix-transpose)= ### linalg.matrix_transpose(x, /) -Alias for {ref}`function-matrix-transpose`. +Alias for {func}`signatures.linear_algebra_functions.matrix_transpose`. (function-linalg-outer)= ### linalg.outer(x1, x2, /) @@ -537,7 +537,7 @@ Returns the singular values of a matrix (or a stack of matrices) `x`. (function-linalg-tensordot)= ### linalg.tensordot(x1, x2, /, *, axes=2) -Alias for {ref}`function-tensordot`. +Alias for {func}`signatures.linear_algebra_functions.tensordot`. (function-linalg-trace)= ### linalg.trace(x, /, *, offset=0) @@ -575,7 +575,7 @@ Returns the sum along the specified diagonals of a matrix (or a stack of matrice (function-linalg-vecdot)= ### linalg.vecdot(x1, x2, /, *, axis=-1) -Alias for {ref}`function-vecdot`. +Alias for {func}`signatures.linear_algebra_functions.vecdot`. (function-linalg-vector-norm)= ### linalg.vector_norm(x, /, *, axis=None, keepdims=False, ord=2) From cbbab62922ab7ddd4f31302c21f22d2db62d6f16 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 27 Jan 2022 00:41:15 -0500 Subject: [PATCH 170/551] Transform linear algebra functions extension md to rst --- .../extension_linear_algebra_functions.py | 498 ++++++++++++++ spec/extensions/linear_algebra_functions.md | 624 ------------------ spec/extensions/linear_algebra_functions.rst | 110 +++ 3 files changed, 608 insertions(+), 624 deletions(-) create mode 100644 spec/API_specification/signatures/extension_linear_algebra_functions.py delete mode 100644 spec/extensions/linear_algebra_functions.md create mode 100644 spec/extensions/linear_algebra_functions.rst diff --git a/spec/API_specification/signatures/extension_linear_algebra_functions.py b/spec/API_specification/signatures/extension_linear_algebra_functions.py new file mode 100644 index 000000000..3235edf13 --- /dev/null +++ b/spec/API_specification/signatures/extension_linear_algebra_functions.py @@ -0,0 +1,498 @@ +from ._types import Literal, Optional, Tuple, Union, array +from .constants import inf +from collections.abc import Sequence + +def cholesky(x: array, /, *, upper: bool = False) -> array: + """ + Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symmetric positive-definite matrix (or a stack of matrices) ``x``, where ``L`` is a lower-triangular matrix or a stack of matrices (``U`` is an upper-triangular matrix or a stack of matrices). + + .. + NOTE: once complex numbers are supported, each square matrix must be Hermitian. + + .. note:: + Whether an array library explicitly checks whether an input array is a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square symmetric positive-definite matrices. Should have a floating-point data type. + upper: bool + If ``True``, the result must be the upper-triangular Cholesky factor ``U``. If ``False``, the result must be the lower-triangular Cholesky factor ``L``. Default: ``False``. + + Returns + ------- + out: array + an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + """ + +def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: + """ + Returns the cross product of 3-element vectors. If ``x1`` and ``x2`` are multi-dimensional arrays (i.e., both have a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must have the same shape as ``x1``. Should have a numeric data type. + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. If set to ``-1``, the function computes the cross product for vectors defined by the last axis (dimension). Default: ``-1``. + + Returns + ------- + out: array + an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def det(x: array, /) -> array: + """ + Returns the determinant of a square matrix (or a stack of square matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + """ + +def diagonal(x: array, /, *, offset: int = 0) -> array: + """ + Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: `0`. + + Returns + ------- + out: array + an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. + """ + +def eigh(x: array, /) -> Tuple[array]: + """ + Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) ``x``, where ``Q`` is an orthogonal matrix (or a stack of matrices) and ``L`` is a vector (or a stack of vectors). + + .. note:: + The function ``eig`` will be added in a future version of the specification, as it requires complex number support. + + .. + NOTE: once complex numbers are supported, each square matrix must be Hermitian. + + .. note:: + Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. + + Returns + ------- + out: Tuple[array] + a namedtuple (``eigenvalues``, ``eigenvectors``) whose + + - first element must have the field name ``eigenvalues`` (corresponding to ``L`` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)``. + - second element have have the field name ``eigenvectors`` (corresponding to ``Q`` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)``. + + Each returned array must have the same floating-point data type as ``x``. + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + """ + +def eigvalsh(x: array, /) -> array: + """ + Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) ``x``. + + .. note:: + The function ``eigvals`` will be added in a future version of the specification, as it requires complex number support. + + .. + NOTE: once complex numbers are supported, each square matrix must be Hermitian. + + .. note:: + Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. + + Returns + ------- + out: array + an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have the same data type as ``x``. + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + """ + +def inv(x: array, /) -> array: + """ + Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + """ + +def matmul(x1: array, x2: array, /) -> array: + """ + Alias for :func:`signatures.linear_algebra_functions.matmul`. + """ + +def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: + """ + Computes the matrix norm of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + keepdims: bool + If ``True``, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the last two axes (dimensions) must not be included in the result. Default: ``False``. + ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] + order of the norm. The following mathematical norms must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | 'fro' | Frobenius norm | + +------------------+---------------------------------+ + | 'nuc' | nuclear norm | + +------------------+---------------------------------+ + | 1 | max(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | 2 | largest singular value | + +------------------+---------------------------------+ + | inf | max(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | -1 | min(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | -2 | smallest singular value | + +------------------+---------------------------------+ + | -inf | min(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + If ``ord=1``, the norm corresponds to the induced matrix norm where ``p=1`` (i.e., the maximum absolute value column sum). + + If ``ord=2``, the norm corresponds to the induced matrix norm where ``p=inf`` (i.e., the maximum absolute value row sum). + + If ``ord=inf``, the norm corresponds to the induced matrix norm where ``p=2`` (i.e., the largest singular value). + + Default: ``'fro'``. + + Returns + ------- + out: array + an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def matrix_power(x: array, n: int, /) -> array: + """ + Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + n: int + integer exponent. + + Returns + ------- + out: array + if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + """ + +def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + """ + Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the ranks. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + """ + +def matrix_transpose(x: array, /) -> array: + """ + Alias for :func:`signatures.linear_algebra_functions.matrix_transpose`. + """ + +def outer(x1: array, x2: array, /) -> array: + """ + Returns the outer product of two vectors ``x1`` and ``x2``. + + Parameters + ---------- + x1: array + first one-dimensional input array of size ``N``. Should have a numeric data type. + x2: array + second one-dimensional input array of size ``M``. Should have a numeric data type. + + Returns + ------- + out: array + a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + """ + Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the pseudo-inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + """ + +def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tuple[array, array]: + """ + Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where ``Q`` is an orthonormal matrix (or a stack of matrices) and ``R`` is an upper-triangular matrix (or a stack of matrices). + + .. note:: + Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a floating-point data type. + mode: Literal['reduced', 'complete'] + decomposition mode. Should be one of the following modes: + + - ``'reduced'``: compute only the leading ``K`` columns of ``q``, such that ``q`` and ``r`` have dimensions ``(..., M, K)`` and ``(..., K, N)``, respectively, and where ``K = min(M, N)``. + - ``'complete'``: compute ``q`` and ``r`` with dimensions ``(..., M, M)`` and ``(..., M, N)``, respectively. + + Default: ``'reduced'``. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(Q, R)`` whose + + - first element must have the field name ``Q`` and must be an array whose shape depends on the value of ``mode`` and contain matrices with orthonormal columns. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, M)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input array ``x``. + - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. + + Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def slogdet(x: array, /) -> Tuple[array, array]: + """ + Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. + + .. note:: + The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling ``det`` may overflow or underflow. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array, array] + a namedtuple (``sign``, ``logabsdet``) whose + + - first element must have the field name ``sign`` and must be an array containing a number representing the sign of the determinant for each square matrix. + - second element must have the field name ``logabsdet`` and must be an array containing the determinant for each square matrix. + + For a real matrix, the sign of the determinant must be either ``1``, ``0``, or ``-1``. + + Each returned array must have shape ``shape(x)[:-2]`` and a floating-point data type determined by :ref:`type-promotion`. + + .. note:: + If a determinant is zero, then the corresponding ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to ``sign * exp(logsabsdet)`` (although, again, the result may be subject to numerical precision errors). + """ + +def solve(x1: array, x2: array, /) -> array: + """ + Returns the solution to the system of linear equations represented by the well-determined (i.e., full rank) linear matrix equation ``AX = B``. + + .. note:: + Whether an array library explicitly checks whether an input array is full rank is implementation-defined. + + Parameters + ---------- + x1: array + coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. + x2: array + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: + """ + Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) ``x``, where ``U`` is a matrix (or a stack of matrices) with orthonormal columns, ``S`` is a vector of non-negative numbers (or stack of vectors), and ``Vh`` is a matrix (or a stack of matrices) with orthonormal rows. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + full_matrices: bool + If ``True``, compute full-sized ``U`` and ``Vh``, such that ``U`` has shape ``(..., M, M)`` and ``Vh`` has shape ``(..., N, N)``. If ``False``, compute on the leading ``K`` singular vectors, such that ``U`` has shape ``(..., M, K)`` and ``Vh`` has shape ``(..., K, N)`` and where ``K = min(M, N)``. Default: ``True``. + + Returns + ------- + .. + NOTE: once complex numbers are supported, each square matrix must be Hermitian. + out: Union[array, Tuple[array, ...]] + a namedtuple ``(U, S, Vh)`` whose + + - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. + - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. + - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. + + Each returned array must have the same floating-point data type as ``x``. + """ + +def svdvals(x: array, /) -> array: + """ + Returns the singular values of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + + Returns + ------- + out: array + an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have the same floating-point data type as ``x``. + """ + +def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + """ + Alias for :func:`signatures.linear_algebra_functions.tensordot`. + """ + +def trace(x: array, /, *, offset: int = 0) -> array: + """ + Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a numeric data type. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: ``0``. + + Returns + ------- + out: array + an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if ``x`` has rank ``k`` and shape ``(I, J, K, ..., L, M, N)``, then an output array has rank ``k-2`` and shape ``(I, J, K, ..., L)`` where + + :: + + out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) + + The returned array must have the same data type as ``x``. + """ + +def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: + """ + Alias for :func:`signatures.linear_algebra_functions.vecdot`. + """ + +def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: + """ + Computes the vector norm of a vector (or batch of vectors) ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + If an integer, ``axis`` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, ``axis`` specifies the axes (dimensions) along which to compute batched vector norms. If ``None``, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: ``None``. + keepdims: bool + If ``True``, the axes (dimensions) specified by ``axis`` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the axes (dimensions) specified by ``axis`` must not be included in the result. Default: ``False``. + ord: Union[int, float, Literal[inf, -inf]] + order of the norm. The following mathematical norms must be supported: + + +------------------+----------------------------+ + | ord | description | + +==================+============================+ + | 1 | L1-norm (Manhattan) | + +------------------+----------------------------+ + | 2 | L2-norm (Euclidean) | + +------------------+----------------------------+ + | inf | infinity norm | + +------------------+----------------------------+ + | (int,float >= 1) | p-norm | + +------------------+----------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+--------------------------------+ + | ord | description | + +==================+================================+ + | 0 | sum(a != 0) | + +------------------+--------------------------------+ + | -1 | 1./sum(1./abs(a)) | + +------------------+--------------------------------+ + | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | + +------------------+--------------------------------+ + | -inf | min(abs(a)) | + +------------------+--------------------------------+ + | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | + +------------------+--------------------------------+ + + Default: ``2``. + + Returns + ------- + out: array + an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +__all__ = ['cholesky', 'cross', 'det', 'diagonal', 'eigh', 'eigvalsh', 'inv', 'matmul', 'matrix_norm', 'matrix_power', 'matrix_rank', 'matrix_transpose', 'outer', 'pinv', 'qr', 'slogdet', 'solve', 'svd', 'svdvals', 'tensordot', 'trace', 'vecdot', 'vector_norm'] diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md deleted file mode 100644 index 6bdcdbd78..000000000 --- a/spec/extensions/linear_algebra_functions.md +++ /dev/null @@ -1,624 +0,0 @@ -(linear-algebra-extension)= -# Linear Algebra Extension - -> Array API specification for linear algebra functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -## Design Principles - -A principal goal of this specification is to standardize commonly implemented interfaces among array libraries. While this specification endeavors to avoid straying too far from common practice, this specification does, with due restraint, seek to address design decisions arising more from historical accident than first principles. This is especially true for linear algebra APIs, which have arisen and evolved organically over time and have often been tied to particular underlying implementations (e.g., to BLAS and LAPACK). - -Accordingly, the standardization process affords the opportunity to reduce interface complexity among linear algebra APIs by inferring and subsequently codifying common design themes, thus allowing more consistent APIs. What follows is the set of design principles governing the APIs which follow: - -1. **Batching**: if an operation is explicitly defined in terms of matrices (i.e., two-dimensional arrays), then the associated interface should support "batching" (i.e., the ability to perform the operation over a "stack" of matrices). Example operations include: - - - `inv`: computing the multiplicative inverse of a square matrix. - - `cholesky`: performing Cholesky decomposition. - - `matmul`: performing matrix multiplication. - -2. **Data types**: if an operation requires decimal operations and {ref}`type-promotion` semantics are undefined (e.g., as is the case for mixed-kind promotions), then the associated interface should be specified as being restricted to floating-point data types. While the specification uses the term "SHOULD" rather than "MUST", a conforming implementation of the array API standard should only ignore the restriction provided overly compelling reasons for doing so. Example operations which should be limited to floating-point data types include: - - - `inv`: computing the multiplicative inverse. - - `slogdet`: computing the natural logarithm of the absolute value of the determinant. - - `norm`: computing the matrix or vector norm. - - Certain operations are solely comprised of multiplications and additions. Accordingly, associated interfaces need not be restricted to floating-point data types. However, careful consideration should be given to overflow, and use of floating-point data types may be more prudent in practice. Example operations include: - - - `matmul`: performing matrix multiplication. - - `trace`: computing the sum along the diagonal. - - `cross`: computing the vector cross product. - - Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: - - - `matrix_transpose`: computing the transpose. - - `diagonal`: returning the diagonal. - -3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. - - In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - - `eig`: computing both eigenvalues and eignvectors. - - `eigvals`: computing only eigenvalues. - -4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. - - Historically, at a time when all array computing happened on CPUs, BLAS and LAPACK underpinned most numerical computing libraries and environments. Naturally, language and library abstractions catered to the parameterization of those libraries, often exposing low-level implementation details verbatim in their higher-level interfaces, even if such choices would be considered poor or ill-advised by today's standards (e.g., NumPy's use of `UPLO` in `eigh`). However, the present day is considerably different. While still important, BLAS and LAPACK no longer hold a monopoly over linear algebra operations, especially given the proliferation of devices and hardware on which such operations must be performed. Accordingly, interfaces must be conservative in the parameterization they support in order to best ensure universality. Such conservatism applies even to performance optimization parameters afforded by certain hardware. - -5. **Orthogonality**: an interface should have clearly defined and delineated functionality which, ideally, has no overlap with the functionality of other interfaces in the specification. Providing multiple interfaces which can all perform the same operation creates unnecessary confusion regarding interface applicability (i.e., which interface is best at which time) and decreases readability of both library and user code. Where overlap is possible, the specification must be parsimonious in the number of interfaces, ensuring that each interface provides a unique and compelling abstraction. Examples of related interfaces which provide distinct levels of abstraction (and generality) include: - - - `vecdot`: computing the dot product of two vectors. - - `matmul`: performing matrix multiplication (including between two vectors and thus the dot product). - - `tensordot`: computing tensor contractions (generalized sum-products). - - `einsum`: expressing operations in terms of Einstein summation convention, including dot products and tensor contractions. - - The above can be contrasted with, e.g., NumPy, which provides the following interfaces for computing the dot product or related operations: - - - `dot`: dot product, matrix multiplication, and tensor contraction. - - `inner`: dot product. - - `vdot`: dot product with flattening and complex conjugation. - - `multi_dot`: chained dot product. - - `tensordot`: tensor contraction. - - `matmul`: matrix multiplication (dot product for two vectors). - - `einsum`: Einstein summation convention. - - where `dot` is overloaded based on input array dimensionality and `vdot` and `inner` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. - -## Objects in API - - - -(function-linalg-cholesky)= -### linalg.cholesky(x, /, *, upper=False) - -Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symmetric positive-definite matrix (or a stack of matrices) `x`, where `L` is a lower-triangular matrix or a stack of matrices (`U` is an upper-triangular matrix or a stack of matrices). - - - -```{note} -Whether an array library explicitly checks whether an input array is a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square symmetric positive-definite matrices. Should have a floating-point data type. - -- **upper**: _bool_ - - - If `True`, the result must be the upper-triangular Cholesky factor `U`. If `False`, the result must be the lower-triangular Cholesky factor `L`. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the Cholesky factors for each square matrix. If `upper` is `False`, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have the same shape as `x`. - -(function-linalg-cross)= -### linalg.cross(x1, x2, /, *, axis=-1) - -Returns the cross product of 3-element vectors. If `x1` and `x2` are multi-dimensional arrays (i.e., both have a rank greater than `1`), then the cross-product of each pair of corresponding 3-element vectors is independently computed. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must have the same shape as `x1`. Should have a numeric data type. - -- **axis**: _int_ - - - the axis (dimension) of `x1` and `x2` containing the vectors for which to compute the cross product. If set to `-1`, the function computes the cross product for vectors defined by the last axis (dimension). Default: `-1`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the cross products. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-linalg-det)= -### linalg.det(x, /) - -Returns the determinant of a square matrix (or a stack of square matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - if `x` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as `x`. - -(function-linalg-diagonal)= -### linalg.diagonal(x, /, *, offset=0) - -Returns the specified diagonals of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. - -- **offset**: _int_ - - - offset specifying the off-diagonal relative to the main diagonal. - - - `offset = 0`: the main diagonal. - - `offset > 0`: off-diagonal above the main diagonal. - - `offset < 0`: off-diagonal below the main diagonal. - - Default: `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as `x`. - -(function-linalg-eigh)= -### linalg.eigh(x, /) - -```{note} -The function `eig` will be added in a future version of the specification, as it requires complex number support. -``` - -Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) `x`, where `Q` is an orthogonal matrix (or a stack of matrices) and `L` is a vector (or a stack of vectors). - - - -```{note} -Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must have a floating-point data type. - -#### Returns - -- **out**: _Tuple\[ <array> ]_ - - - a namedtuple (`eigenvalues`, `eigenvectors`) whose - - - first element must have the field name `eigenvalues` (corresponding to `L` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape `(..., M)`. - - second element have have the field name `eigenvectors` (corresponding to `Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape `(..., M, M)`. - - Each returned array must have the same floating-point data type as `x`. - -```{note} -Eigenvalue sort order is left unspecified and is thus implementation-dependent. -``` - -(function-linalg-eigvalsh)= -### linalg.eigvalsh(x, /) - -```{note} -The function `eigvals` will be added in a future version of the specification, as it requires complex number support. -``` - -Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) `x`. - - - -```{note} -Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the computed eigenvalues. The returned array must have shape `(..., M)` and have the same data type as `x`. - -```{note} -Eigenvalue sort order is left unspecified and is thus implementation-dependent. -``` - -(function-linalg-inv)= -### linalg.inv(x, /) - -Returns the multiplicative inverse of a square matrix (or a stack of square matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have the same shape as `x`. - -(function-linalg-matmul)= -### linalg.matmul(x1, x2, /) - -Alias for {ref}`function-matmul`. - -(function-linalg-matrix-norm)= -### linalg.matrix_norm(x, /, *, keepdims=False, ord='fro') - -Computes the matrix norm of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - -- **keepdims**: _bool_ - - - If `True`, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the last two axes (dimensions) must not be included in the result. Default: `False`. - -- **ord**: _Optional\[ Union\[ int, float, Literal\[ inf, -inf, 'fro', 'nuc' ] ] ]_ - - - order of the norm. The following mathematical norms must be supported: - | ord | description | - | ---------------- | ------------------------------- | - | 'fro' | Frobenius norm | - | 'nuc' | nuclear norm | - | 1 | max(sum(abs(x), axis=0)) | - | 2 | largest singular value | - | inf | max(sum(abs(x), axis=1)) | - - The following non-mathematical "norms" must be supported: - | ord | description | - | ---------------- | ------------------------------- | - | -1 | min(sum(abs(x), axis=0)) | - | -2 | smallest singular value | - | -inf | min(sum(abs(x), axis=1)) | - - If `ord=1`, the norm corresponds to the induced matrix norm where `p=1` (i.e., the maximum absolute value column sum). - - If `ord=2`, the norm corresponds to the induced matrix norm where `p=inf` (i.e., the maximum absolute value row sum). - - If `ord=inf`, the norm corresponds to the induced matrix norm where `p=2` (i.e., the largest singular value). - - Default: `'fro'`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the norms for each `MxN` matrix. If `keepdims` is `False`, the returned array must have a rank which is two less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-matrix_power)= -### linalg.matrix_power(x, n, /) - -Raises a square matrix (or a stack of square matrices) `x` to an integer power `n`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -- **n**: _int_ - - - integer exponent. - -#### Returns - -- **out**: _<array>_ - - - if `n` is equal to zero, an array containing the identity matrix for each square matrix. If `n` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of `n`, provided that each square matrix is invertible. If `n` is greater than zero, an array containing the result of raising each square matrix to the power `n`. The returned array must have the same shape as `x` and a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-matrix_rank)= -### linalg.matrix_rank(x, /, *, rtol=None) - -Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - -- **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - - relative tolerance for small singular values. Singular values approximately less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the ranks. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have shape `(...)` (i.e., must have a shape equal to `shape(x)[:-2]`). - -(function-linalg-matrix-transpose)= -### linalg.matrix_transpose(x, /) - -Alias for {ref}`function-matrix-transpose`. - -(function-linalg-outer)= -### linalg.outer(x1, x2, /) - -Returns the outer product of two vectors `x1` and `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first one-dimensional input array of size `N`. Should have a numeric data type. - -- **x2**: _<array>_ - - - second one-dimensional input array of size `M`. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - a two-dimensional array containing the outer product and whose shape is `(N, M)`. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-linalg-pinv)= -### linalg.pinv(x, /, *, rtol=None) - -Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - -- **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - - relative tolerance for small singular values. Singular values approximately less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the pseudo-inverses. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have shape `(..., N, M)` (i.e., must have the same shape as `x`, except the innermost two dimensions must be transposed). - -(function-linalg-qr)= -### linalg.qr(x, /, *, mode='reduced') - -Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where `Q` is an orthonormal matrix (or a stack of matrices) and `R` is an upper-triangular matrix (or a stack of matrices). - -```{note} -Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices of rank `N`. Should have a floating-point data type. - -- **mode**: _Literal\[ 'reduced', 'complete' ]_ - - - decomposition mode. Should be one of the following modes: - - - `'reduced'`: compute only the leading `K` columns of `q`, such that `q` and `r` have dimensions `(..., M, K)` and `(..., K, N)`, respectively, and where `K = min(M, N)`. - - `'complete'`: compute `q` and `r` with dimensions `(..., M, M)` and `(..., M, N)`, respectively. - - Default: `'reduced'`. - -#### Returns - -- **out**: _Tuple\[ <array>, <array> ]_ - - - a namedtuple `(Q, R)` whose - - - first element must have the field name `Q` and must be an array whose shape depends on the value of `mode` and contain matrices with orthonormal columns. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input array `x`. - - second element must have the field name `R` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, N)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. - - Each returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-slogdet)= -### linalg.slogdet(x, /) - -Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) `x`. - -```{note} -The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling `det` may overflow or underflow. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -#### Returns - -- **out**: _Tuple\[ <array>, <array> ]_ - - - a namedtuple (`sign`, `logabsdet`) whose - - - first element must have the field name `sign` and must be an array containing a number representing the sign of the determinant for each square matrix. - - second element must have the field name `logabsdet` and must be an array containing the determinant for each square matrix. - - For a real matrix, the sign of the determinant must be either `1`, `0`, or `-1`. - - Each returned array must have shape `shape(x)[:-2]` and a floating-point data type determined by {ref}`type-promotion`. - - ```{note} - If a determinant is zero, then the corresponding `sign` should be `0` and `logabsdet` should be `-infinity`; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to `sign * exp(logsabsdet)` (although, again, the result may be subject to numerical precision errors). - ``` - -(function-linalg-solve)= -### linalg.solve(x1, x2, /) - -Returns the solution to the system of linear equations represented by the well-determined (i.e., full rank) linear matrix equation `AX = B`. - -```{note} -Whether an array library explicitly checks whether an input array is full rank is implementation-defined. -``` - -#### Parameters - -- **x1**: _<array>_ - - - coefficient array `A` having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. - -- **x2**: _<array>_ - - - ordinate (or "dependent variable") array `B`. If `x2` has shape `(M,)`, `x2` is equivalent to an array having shape `(..., M, 1)`. If `x2` has shape `(..., M, K)`, each column `k` defines a set of ordinate values for which to compute a solution, and `shape(x2)[:-1]` must be compatible with `shape(x1)[:-1]` (see {ref}`broadcasting`). Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the solution to the system `AX = B` for each square matrix. The returned array must have the same shape as `x2` (i.e., the array corresponding to `B`) and must have a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-svd)= -### linalg.svd(x, /, *, full_matrices=True) - -Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) `x`, where `U` is a matrix (or a stack of matrices) with orthonormal columns, `S` is a vector of non-negative numbers (or stack of vectors), and `Vh` is a matrix (or a stack of matrices) with orthonormal rows. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. - -- **full_matrices**: _bool_ - - - If `True`, compute full-sized `U` and `Vh`, such that `U` has shape `(..., M, M)` and `Vh` has shape `(..., N, N)`. If `False`, compute on the leading `K` singular vectors, such that `U` has shape `(..., M, K)` and `Vh` has shape `(..., K, N)` and where `K = min(M, N)`. Default: `True`. - -#### Returns - - - -- **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ - - - a namedtuple `(U, S, Vh)` whose - - - first element must have the field name `U` and must be an array whose shape depends on the value of `full_matrices` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - second element must have the field name `S` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`, where `K = min(M, N)`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - third element must have the field name `Vh` and must be an array whose shape depends on the value of `full_matrices` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - Each returned array must have the same floating-point data type as `x`. - -(function-linalg-svdvals)= -### linalg.svdvals(x, /) - -Returns the singular values of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`, where `K = min(M, N)`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. The returned array must have the same floating-point data type as `x`. - -(function-linalg-tensordot)= -### linalg.tensordot(x1, x2, /, *, axes=2) - -Alias for {ref}`function-tensordot`. - -(function-linalg-trace)= -### linalg.trace(x, /, *, offset=0) - -Returns the sum along the specified diagonals of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a numeric data type. - -- **offset**: _int_ - - - offset specifying the off-diagonal relative to the main diagonal. - - - `offset = 0`: the main diagonal. - - `offset > 0`: off-diagonal above the main diagonal. - - `offset < 0`: off-diagonal below the main diagonal. - - Default: `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if `x` has rank `k` and shape `(I, J, K, ..., L, M, N)`, then an output array has rank `k-2` and shape `(I, J, K, ..., L)` where - - ```text - out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) - ``` - - The returned array must have the same data type as `x`. - -(function-linalg-vecdot)= -### linalg.vecdot(x1, x2, /, *, axis=-1) - -Alias for {ref}`function-vecdot`. - -(function-linalg-vector-norm)= -### linalg.vector_norm(x, /, *, axis=None, keepdims=False, ord=2) - -Computes the vector norm of a vector (or batch of vectors) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - If an integer, `axis` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, `axis` specifies the axes (dimensions) along which to compute batched vector norms. If `None`, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the axes (dimensions) specified by `axis` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the axes (dimensions) specified by `axis` must not be included in the result. Default: `False`. - -- **ord**: _Union\[ int, float, Literal\[ inf, -inf ] ]_ - - - order of the norm. The following mathematical norms must be supported: - | ord | description | - | ---------------- | -------------------------- | - | 1 | L1-norm (Manhattan) | - | 2 | L2-norm (Euclidean) | - | inf | infinity norm | - | (int,float >= 1) | p-norm | - - The following non-mathematical "norms" must be supported: - | ord | description | - | ---------------- | ------------------------------ | - | 0 | sum(a != 0) | - | -1 | 1./sum(1./abs(a)) | - | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | - | -inf | min(abs(a)) | - | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | - - Default: `2`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the vector norms. If `axis` is `None`, the returned array must be a zero-dimensional array containing a vector norm. If `axis` is a scalar value (`int` or `float`), the returned array must have a rank which is one less than the rank of `x`. If `axis` is a `n`-tuple, the returned array must have a rank which is `n` less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/extensions/linear_algebra_functions.rst new file mode 100644 index 000000000..8ad1ad487 --- /dev/null +++ b/spec/extensions/linear_algebra_functions.rst @@ -0,0 +1,110 @@ +.. _linear-algebra-extension: + +Linear Algebra Extension +======================== + + Array API specification for linear algebra functions. + +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`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. + +Design Principles +----------------- + +A principal goal of this specification is to standardize commonly implemented interfaces among array libraries. While this specification endeavors to avoid straying too far from common practice, this specification does, with due restraint, seek to address design decisions arising more from historical accident than first principles. This is especially true for linear algebra APIs, which have arisen and evolved organically over time and have often been tied to particular underlying implementations (e.g., to BLAS and LAPACK). + +Accordingly, the standardization process affords the opportunity to reduce interface complexity among linear algebra APIs by inferring and subsequently codifying common design themes, thus allowing more consistent APIs. What follows is the set of design principles governing the APIs which follow: + +1. **Batching**: if an operation is explicitly defined in terms of matrices (i.e., two-dimensional arrays), then the associated interface should support "batching" (i.e., the ability to perform the operation over a "stack" of matrices). Example operations include: + + - ``inv``: computing the multiplicative inverse of a square matrix. + - ``cholesky``: performing Cholesky decomposition. + - ``matmul``: performing matrix multiplication. + +2. **Data types**: if an operation requires decimal operations and :ref:`type-promotion` semantics are undefined (e.g., as is the case for mixed-kind promotions), then the associated interface should be specified as being restricted to floating-point data types. While the specification uses the term "SHOULD" rather than "MUST", a conforming implementation of the array API standard should only ignore the restriction provided overly compelling reasons for doing so. Example operations which should be limited to floating-point data types include: + + - ``inv``: computing the multiplicative inverse. + - ``slogdet``: computing the natural logarithm of the absolute value of the determinant. + - ``norm``: computing the matrix or vector norm. + + Certain operations are solely comprised of multiplications and additions. Accordingly, associated interfaces need not be restricted to floating-point data types. However, careful consideration should be given to overflow, and use of floating-point data types may be more prudent in practice. Example operations include: + + - ``matmul``: performing matrix multiplication. + - ``trace``: computing the sum along the diagonal. + - ``cross``: computing the vector cross product. + + Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: + + - ``matrix_transpose``: computing the transpose. + - ``diagonal``: returning the diagonal. + +3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. + + In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: + + - ``eig``: computing both eigenvalues and eignvectors. + - ``eigvals``: computing only eigenvalues. + +4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. + + Historically, at a time when all array computing happened on CPUs, BLAS and LAPACK underpinned most numerical computing libraries and environments. Naturally, language and library abstractions catered to the parameterization of those libraries, often exposing low-level implementation details verbatim in their higher-level interfaces, even if such choices would be considered poor or ill-advised by today's standards (e.g., NumPy's use of `UPLO` in `eigh`). However, the present day is considerably different. While still important, BLAS and LAPACK no longer hold a monopoly over linear algebra operations, especially given the proliferation of devices and hardware on which such operations must be performed. Accordingly, interfaces must be conservative in the parameterization they support in order to best ensure universality. Such conservatism applies even to performance optimization parameters afforded by certain hardware. + +5. **Orthogonality**: an interface should have clearly defined and delineated functionality which, ideally, has no overlap with the functionality of other interfaces in the specification. Providing multiple interfaces which can all perform the same operation creates unnecessary confusion regarding interface applicability (i.e., which interface is best at which time) and decreases readability of both library and user code. Where overlap is possible, the specification must be parsimonious in the number of interfaces, ensuring that each interface provides a unique and compelling abstraction. Examples of related interfaces which provide distinct levels of abstraction (and generality) include: + + - ``vecdot``: computing the dot product of two vectors. + - ``matmul``: performing matrix multiplication (including between two vectors and thus the dot product). + - ``tensordot``: computing tensor contractions (generalized sum-products). + - ``einsum``: expressing operations in terms of Einstein summation convention, including dot products and tensor contractions. + + The above can be contrasted with, e.g., NumPy, which provides the following interfaces for computing the dot product or related operations: + + - ``dot``: dot product, matrix multiplication, and tensor contraction. + - ``inner``: dot product. + - ``vdot``: dot product with flattening and complex conjugation. + - ``multi_dot``: chained dot product. + - ``tensordot``: tensor contraction. + - ``matmul``: matrix multiplication (dot product for two vectors). + - ``einsum``: Einstein summation convention. + + where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. + +.. currentmodule:: signatures.extension_linear_algebra_functions + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cholesky + cross + det + diagonal + eigh + eigvalsh + inv + matmul + matrix_norm + matrix_power + matrix_rank + matrix_transpose + outer + pinv + qr + slogdet + solve + svd + svdvals + tensordot + trace + vecdot + vector_norm From d1d9c0d8a9d471292799eb1840f4d802c5d86afc Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 27 Jan 2022 14:09:42 -0500 Subject: [PATCH 171/551] Upgrade to python 3.10.2 --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 829dcbb64..ad1ce36ec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -5,7 +5,7 @@ _defaults: &defaults docker: # CircleCI maintains a library of pre-built images # documented at https://circleci.com/docs/2.0/circleci-images/ - - image: circleci/python:3.8.0 + - image: cimg/python:3.10.2 working_directory: ~/repo jobs: From 6a0eab7801d1fe1b010b95881ef27513cc79ed95 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 27 Jan 2022 14:11:40 -0500 Subject: [PATCH 172/551] Remove sudo --- .circleci/config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ad1ce36ec..f27e3e5ec 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,7 +19,7 @@ jobs: name: build docs no_output_timeout: 25m command: | - sudo pip install -r requirements.txt + pip install -r requirements.txt sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - store_artifacts: path: build/latest From 5221c7076cecbd4c36875be4dd2de71c041643a5 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 27 Jan 2022 14:14:04 -0500 Subject: [PATCH 173/551] Upgrade github actions to python 3.10.2 --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 77357707a..67bafdb25 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -15,7 +15,7 @@ jobs: - uses: actions/checkout@master - uses: actions/setup-python@v2 with: - python-version: '3.8' # Version range or exact version of a Python version to use, using semvers version range syntax. + python-version: '3.10.2' # Version range or exact version of a Python version to use, using semvers version range syntax. architecture: 'x64' # (x64 or x86) - run: | # add dependencies based on the conf.py From 8a3620756b2507e62c5115ebe94913e4436fcd6b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 31 Jan 2022 03:38:13 -0500 Subject: [PATCH 174/551] PR: Transform device support md to rst (#379) * Transform device support md to rst * Update url --- spec/design_topics/device_support.md | 116 -------------------------- spec/design_topics/device_support.rst | 111 ++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 116 deletions(-) delete mode 100644 spec/design_topics/device_support.md create mode 100644 spec/design_topics/device_support.rst diff --git a/spec/design_topics/device_support.md b/spec/design_topics/device_support.md deleted file mode 100644 index 454171731..000000000 --- a/spec/design_topics/device_support.md +++ /dev/null @@ -1,116 +0,0 @@ -(device-support)= - -# Device support - -For libraries that support execution on more than a single hardware device - e.g. CPU and GPU, or multiple GPUs - it is important to be able to control on which device newly created arrays get placed and where execution happens. Attempting to be fully implicit doesn't always scale well to situations with multiple GPUs. - -Existing libraries employ one or more of these three methods to exert such control over data placement: - -1. A global default device, which may be fixed or user-switchable. -2. A context manager to control device assignment within its scope. -3. Local control for data allocation target device via explicit keywords, and a method to transfer arrays to another device. - -Libraries differ in how execution is controlled, via a context manager or with the convention that execution takes place on the same device where all argument arrays are allocated. And they may or may not allow mixing arrays on different devices via implicit data transfers. - -This standard chooses to add support for method 3 (local control), with the convention that execution takes place on the same device where all argument arrays are allocated. The rationale for choosing method 3 is because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see {ref}`device-out-of-scope` for details. - - -## Intended usage - -The intended usage for the device support in the current version of the -standard is _device handling in library code_. The assumed pattern is that -users create arrays (for which they can use all the relevant device syntax -that the library they use provides), and that they then pass those arrays -into library code which may have to do the following: - -- Create new arrays on the same device as an array that's passed in. -- Determine whether two input arrays are present on the same device or not. -- Move an array from one device to another. -- Create output arrays on the same device as the input arrays. -- Pass on a specified device to other library code. - -```{note} -Given that there is not much that's currently common in terms of -device-related syntax between different array libraries, the syntax included -in the standard is kept as minimal as possible while enabling the -above-listed use cases. -``` - -## Syntax for device assignment - -The array API will offer the following syntax for device assignment and -cross-device data transfer: - -1. A `.device` property on the array object, which returns a `Device` object - representing the device the data in the array is stored on, and supports - comparing devices for equality with `==` and `!=` within the same library - (e.g., by implementing `__eq__`); comparing device objects from different - libraries is out of scope). -2. A `device=None` keyword for array creation functions, which takes an - instance of a `Device` object. -3. A `.to_device` method on the array object to copy an array to a different device. - -```{note} -In the current API standard, the only way to obtain a `Device` object is from the -`.device` property on the array object. The standard does **not** include a universal -`Device` object recognized by all compliant libraries. Accordingly, the standard does -not provide a means of instantiating a `Device` object to point to a specific physical or -logical device. - -The choice to not include a standardized `Device` object may be revisited in a future revision of this standard. - -For array libraries which concern themselves with multi-device support, including CPU and GPU, -they are free to expose a library-specific device object (e.g., for creating an -array on a particular device). While a library-specific device object can be used as input to -`to_device`, beware that this will mean non-portability as code will be specific to -that library. -``` - - -## Semantics - -Handling devices is complex, and some frameworks have elaborate policies for -handling device placement. Therefore this section only gives recommendations, -rather than hard requirements: - -- Respect explicit device assignment (i.e. if the input to the `device=` keyword - is not `None`, guarantee that the array is created on the given device, and - raise an exception otherwise). -- Preserve device assignment as much as possible (e.g. output arrays from a - function are expected to be on the same device as input arrays to the - function). -- Raise an exception if an operation involves arrays on different devices - (i.e. avoid implicit data transfer between devices). -- Use a default for `device=None` which is consistent between functions - within the same library. -- If a library has multiple ways of controlling device placement, the most - explicit method should have the highest priority. For example: - 1. If `device=` keyword is specified, that always takes precedence - 2. If `device=None`, then use the setting from a context manager, if set. - 3. If no context manager was used, then use the global default device/strategy - - -(device-out-of-scope)= - -## Out of scope for device support - -Individual libraries may offers APIs for one or more of the following topics, -however those are out of scope for this standard: - -- Identifying a specific physical or logical device across libraries -- Setting a default device globally -- Stream/queue control -- Distributed allocation -- Memory pinning -- A context manager for device control - -```{note} -A context manager for controlling the default device is present in most existing array -libraries (NumPy being the exception). There are concerns with using a -context manager however. A context manager can be tricky to use at a high -level, since it may affect library code below function calls (non-local -effects). See, e.g., [this PyTorch issue](https://github.com/pytorch/pytorch/issues/27878) -for a discussion on a good context manager API. - -Adding a context manager may be considered in a future version of this API standard. -``` diff --git a/spec/design_topics/device_support.rst b/spec/design_topics/device_support.rst new file mode 100644 index 000000000..29f0789bb --- /dev/null +++ b/spec/design_topics/device_support.rst @@ -0,0 +1,111 @@ +.. _device-support: + +Device support +============== + +For libraries that support execution on more than a single hardware device - e.g. CPU and GPU, or multiple GPUs - it is important to be able to control on which device newly created arrays get placed and where execution happens. Attempting to be fully implicit doesn't always scale well to situations with multiple GPUs. + +Existing libraries employ one or more of these three methods to exert such control over data placement: + +1. A global default device, which may be fixed or user-switchable. +2. A context manager to control device assignment within its scope. +3. Local control for data allocation target device via explicit keywords, and a method to transfer arrays to another device. + +Libraries differ in how execution is controlled, via a context manager or with the convention that execution takes place on the same device where all argument arrays are allocated. And they may or may not allow mixing arrays on different devices via implicit data transfers. + +This standard chooses to add support for method 3 (local control), with the convention that execution takes place on the same device where all argument arrays are allocated. The rationale for choosing method 3 is because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see :ref:`device-out-of-scope` for details. + +Intended usage +-------------- + +The intended usage for the device support in the current version of the +standard is *device handling in library code*. The assumed pattern is that +users create arrays (for which they can use all the relevant device syntax +that the library they use provides), and that they then pass those arrays +into library code which may have to do the following: + +- Create new arrays on the same device as an array that's passed in. +- Determine whether two input arrays are present on the same device or not. +- Move an array from one device to another. +- Create output arrays on the same device as the input arrays. +- Pass on a specified device to other library code. + +.. note:: + Given that there is not much that's currently common in terms of + device-related syntax between different array libraries, the syntax included + in the standard is kept as minimal as possible while enabling the + above-listed use cases. + +Syntax for device assignment +---------------------------- + +The array API will offer the following syntax for device assignment and +cross-device data transfer: + +1. A ``.device`` property on the array object, which returns a ``Device`` object + representing the device the data in the array is stored on, and supports + comparing devices for equality with ``==`` and ``!=`` within the same library + (e.g., by implementing ``__eq__``); comparing device objects from different + libraries is out of scope). +2. A ``device=None`` keyword for array creation functions, which takes an + instance of a ``Device`` object. +3. A ``.to_device`` method on the array object to copy an array to a different device. + +.. note:: + In the current API standard, the only way to obtain a ``Device`` object is from the + ``.device`` property on the array object. The standard does **not** include a universal + ``Device`` object recognized by all compliant libraries. Accordingly, the standard does + not provide a means of instantiating a ``Device`` object to point to a specific physical or + logical device. + + The choice to not include a standardized ``Device`` object may be revisited in a future revision of this standard. + + For array libraries which concern themselves with multi-device support, including CPU and GPU, + they are free to expose a library-specific device object (e.g., for creating an + array on a particular device). While a library-specific device object can be used as input to + ``to_device``, beware that this will mean non-portability as code will be specific to + that library. + +Semantics +--------- + +Handling devices is complex, and some frameworks have elaborate policies for +handling device placement. Therefore this section only gives recommendations, +rather than hard requirements: + +- Respect explicit device assignment (i.e. if the input to the ``device=`` keyword is not ``None``, guarantee that the array is created on the given device, and raise an exception otherwise). +- Preserve device assignment as much as possible (e.g. output arrays from a function are expected to be on the same device as input arrays to the function). +- Raise an exception if an operation involves arrays on different devices (i.e. avoid implicit data transfer between devices). +- Use a default for ``device=None`` which is consistent between functions within the same library. +- If a library has multiple ways of controlling device placement, the most explicit method should have the highest priority. For example: + + 1. If ``device=`` keyword is specified, that always takes precedence + + 2. If ``device=None``, then use the setting from a context manager, if set. + + 3. If no context manager was used, then use the global default device/strategy + +.. _device-out-of-scope: + +Out of scope for device support +------------------------------- + +Individual libraries may offers APIs for one or more of the following topics, +however those are out of scope for this standard: + +- Identifying a specific physical or logical device across libraries +- Setting a default device globally +- Stream/queue control +- Distributed allocation +- Memory pinning +- A context manager for device control + +.. note:: + A context manager for controlling the default device is present in most existing array + libraries (NumPy being the exception). There are concerns with using a + context manager however. A context manager can be tricky to use at a high + level, since it may affect library code below function calls (non-local + effects). See, e.g., `this PyTorch issue `_ + for a discussion on a good context manager API. + + Adding a context manager may be considered in a future version of this API standard. From 6a106cca4713dc61f19fed4b695121c353bada41 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 31 Jan 2022 03:39:41 -0500 Subject: [PATCH 175/551] PR: Transform type promotion md to rst (#371) * Transform type promotion md to rst * Add missing backticks * Add review changes Co-authored-by: Athan --- spec/API_specification/type_promotion.md | 112 ------------------ spec/API_specification/type_promotion.rst | 136 ++++++++++++++++++++++ 2 files changed, 136 insertions(+), 112 deletions(-) delete mode 100644 spec/API_specification/type_promotion.md create mode 100644 spec/API_specification/type_promotion.rst diff --git a/spec/API_specification/type_promotion.md b/spec/API_specification/type_promotion.md deleted file mode 100644 index d8aedde42..000000000 --- a/spec/API_specification/type_promotion.md +++ /dev/null @@ -1,112 +0,0 @@ -(type-promotion)= - -# Type Promotion Rules - -> Array API specification for type promotion rules. - -Type promotion rules can be understood at a high level from the following diagram: - -![Type promotion diagram](/_static/images/dtype_promotion_lattice.png) - -_Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined._ - - -## Rules - -A conforming implementation of the array API standard must implement the following type promotion rules governing the common result type for two **array** operands during an arithmetic operation. - -A conforming implementation of the array API standard may support additional type promotion rules beyond those described in this specification. - -```{note} -Type codes are used here to keep tables readable; they are not part of the standard. In code, use the data type objects specified in {ref}`data-types` (e.g., `int16` rather than `'i2'`). -``` - - - -The following type promotion tables specify the casting behavior for operations involving two array operands. When more than two array operands participate, application of the promotion tables is associative (i.e., the result does not depend on operand order). - -### Signed integer type promotion table - -| | i1 | i2 | i4 | i8 | -| ------ | -- | -- | -- | -- | -| **i1** | i1 | i2 | i4 | i8 | -| **i2** | i2 | i2 | i4 | i8 | -| **i4** | i4 | i4 | i4 | i8 | -| **i8** | i8 | i8 | i8 | i8 | - -where - -- **i1**: 8-bit signed integer (i.e., `int8`) -- **i2**: 16-bit signed integer (i.e., `int16`) -- **i4**: 32-bit signed integer (i.e., `int32`) -- **i8**: 64-bit signed integer (i.e., `int64`) - -### Unsigned integer type promotion table - -| | u1 | u2 | u4 | u8 | -| ------ | -- | -- | -- | -- | -| **u1** | u1 | u2 | u4 | u8 | -| **u2** | u2 | u2 | u4 | u8 | -| **u4** | u4 | u4 | u4 | u8 | -| **u8** | u8 | u8 | u8 | u8 | - -where - -- **u1**: 8-bit unsigned integer (i.e., `uint8`) -- **u2**: 16-bit unsigned integer (i.e., `uint16`) -- **u4**: 32-bit unsigned integer (i.e., `uint32`) -- **u8**: 64-bit unsigned integer (i.e., `uint64`) - -### Mixed unsigned and signed integer type promotion table - -| | u1 | u2 | u4 | -| ------ | -- | -- | -- | -| **i1** | i2 | i4 | i8 | -| **i2** | i2 | i4 | i8 | -| **i4** | i4 | i4 | i8 | -| **i8** | i8 | i8 | i8 | - -### Floating-point type promotion table - -| | f4 | f8 | -| ------ | -- | -- | -| **f4** | f4 | f8 | -| **f8** | f8 | f8 | - -where - -- **f4**: single-precision (32-bit) floating-point number (i.e., `float32`) -- **f8**: double-precision (64-bit) floating-point number (i.e., `float64`) - -### Notes - -- Type promotion rules must apply when determining the common result type for two **array** operands during an arithmetic operation, regardless of array dimension. Accordingly, zero-dimensional arrays must be subject to the same type promotion rules as dimensional arrays. -- Type promotion of non-numerical data types to numerical data types is unspecified (e.g., `bool` to `intxx` or `floatxx`). - -```{note} -Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. -``` - -### Mixing arrays with Python scalars - -Using Python scalars (i.e., instances of `bool`, `int`, `float`) together with arrays must be supported for: - -- `array scalar` -- `scalar array` - -where `` is a built-in operator (including in-place operators, but excluding the matmul `@` operator; see {ref}`operators` for operators supported by the array object) and `scalar` has a type and value compatible with the array data type: - -- a Python `bool` for a `bool` array data type. -- a Python `int` within the [bounds](data-types) of the given data type for integer array data types. -- a Python `int` or `float` for floating-point array data types. - -Provided the above requirements are met, the expected behavior is equivalent to: - -1. Convert the scalar to zero-dimensional array with the same data type as that of the array used in the expression. -2. Execute the operation for `array 0-D array` (or `0-D array array` if `scalar` was the left-hand argument). - -```{note} -Behavior is not specified when mixing a Python `float` and an array with an integer data type; this may give `float32`, `float64`, or raise an exception. Behavior is implementation-specific. - -The behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. -``` diff --git a/spec/API_specification/type_promotion.rst b/spec/API_specification/type_promotion.rst new file mode 100644 index 000000000..d30f6517c --- /dev/null +++ b/spec/API_specification/type_promotion.rst @@ -0,0 +1,136 @@ +.. _type-promotion: + +Type Promotion Rules +==================== + + Array API specification for type promotion rules. + +Type promotion rules can be understood at a high level from the following diagram: + +.. image:: /_static/images/dtype_promotion_lattice.png + :target: Type promotion diagram + +*Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* + +Rules +----- + +A conforming implementation of the array API standard must implement the following type promotion rules governing the common result type for two **array** operands during an arithmetic operation. + +A conforming implementation of the array API standard may support additional type promotion rules beyond those described in this specification. + +.. note:: + Type codes are used here to keep tables readable; they are not part of the standard. In code, use the data type objects specified in :ref:`data-types` (e.g., ``int16`` rather than ``'i2'``). + +.. + Note: please keep table columns aligned + +The following type promotion tables specify the casting behavior for operations involving two array operands. When more than two array operands participate, application of the promotion tables is associative (i.e., the result does not depend on operand order). + +Signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | i1 | i2 | i4 | i8 | ++========+====+====+====+====+ +| **i1** | i1 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i2** | i2 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i4** | i4 | i4 | i4 | i8 | ++--------+----+----+----+----+ +| **i8** | i8 | i8 | i8 | i8 | ++--------+----+----+----+----+ + +where + +- **i1**: 8-bit signed integer (i.e., ``int8``) +- **i2**: 16-bit signed integer (i.e., ``int16``) +- **i4**: 32-bit signed integer (i.e., ``int32``) +- **i8**: 64-bit signed integer (i.e., ``int64``) + +Unsigned integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | u1 | u2 | u4 | u8 | ++========+====+====+====+====+ +| **u1** | u1 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u2** | u2 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u4** | u4 | u4 | u4 | u8 | ++--------+----+----+----+----+ +| **u8** | u8 | u8 | u8 | u8 | ++--------+----+----+----+----+ + +where + +- **u1**: 8-bit unsigned integer (i.e., ``uint8``) +- **u2**: 16-bit unsigned integer (i.e., ``uint16``) +- **u4**: 32-bit unsigned integer (i.e., ``uint32``) +- **u8**: 64-bit unsigned integer (i.e., ``uint64``) + +Mixed unsigned and signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+ +| | u1 | u2 | u4 | ++========+====+====+====+ +| **i1** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i2** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i4** | i4 | i4 | i8 | ++--------+----+----+----+ +| **i8** | i8 | i8 | i8 | ++--------+----+----+----+ + +Floating-point type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+ +| | f4 | f8 | ++========+====+====+ +| **f4** | f4 | f8 | ++--------+----+----+ +| **f8** | f8 | f8 | ++--------+----+----+ + +where + +- **f4**: single-precision (32-bit) floating-point number (i.e., ``float32``) +- **f8**: double-precision (64-bit) floating-point number (i.e., ``float64``) + +Notes +~~~~~ + +- Type promotion rules must apply when determining the common result type for two **array** operands during an arithmetic operation, regardless of array dimension. Accordingly, zero-dimensional arrays must be subject to the same type promotion rules as dimensional arrays. +- Type promotion of non-numerical data types to numerical data types is unspecified (e.g., ``bool`` to ``intxx`` or ``floatxx``). + +.. note:: + Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. + +Mixing arrays with Python scalars +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using Python scalars (i.e., instances of ``bool``, ``int``, ``float``) together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with the array data type: + +- a Python ``bool`` for a ``bool`` array data type. +- a Python ``int`` within the bounds of the given data type for integer array :ref:`data-types`. +- a Python ``int`` or ``float`` for floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to zero-dimensional array with the same data type as that of the array used in the expression. +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +.. note:: + Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. + + The behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. From 1963b2e4ac95c969acb5bf2094e1ff37b018f59c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 31 Jan 2022 03:49:59 -0500 Subject: [PATCH 176/551] PR: Transform statistical functions md to rst (#370) * Transform statistical functions md to rst * Update note directives * Lowercase first sentence to be consistent with rest of spec This commit addresses an oversight in the spec prior to Markdown to rST conversion. Co-authored-by: Athan --- .../signatures/statistical_functions.py | 235 ++++++++++++++ .../statistical_functions.md | 302 ------------------ .../statistical_functions.rst | 32 ++ 3 files changed, 267 insertions(+), 302 deletions(-) create mode 100644 spec/API_specification/signatures/statistical_functions.py delete mode 100644 spec/API_specification/statistical_functions.md create mode 100644 spec/API_specification/statistical_functions.rst diff --git a/spec/API_specification/signatures/statistical_functions.py b/spec/API_specification/signatures/statistical_functions.py new file mode 100644 index 000000000..4265f28f5 --- /dev/null +++ b/spec/API_specification/signatures/statistical_functions.py @@ -0,0 +1,235 @@ +from ._types import Optional, Tuple, Union, array, dtype + +def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + """ + Calculates the maximum value of the input array ``x``. + + .. note:: + When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. + """ + +def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + """ + Calculates the arithmetic mean of the input array ``x``. + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the arithmetic mean. + + - If ``N`` is ``0``, the arithmetic mean is ``NaN``. + - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. + """ + +def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + """ + Calculates the minimum value of the input array ``x``. + + .. note:: + When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. + """ + +def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + """ + Calculates the product of input array ``x`` elements. + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the product. + + - If ``N`` is ``0``, the product is `1` (i.e., the empty product). + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the product is ``NaN`` (i.e., ``NaN`` values propagate). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. + dtype: Optional[dtype] + data type of the returned array. If ``None``, + + - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + - if ``x`` has a floating-point data type, the returned array must have the default floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product. Default: ``None``. + + .. note:: + This keyword argument is intended to help prevent data type overflows. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. + """ + +def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + """ + Calculates the standard deviation of the input array ``x``. + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the standard deviation. + + - If ``N - correction`` is less than or equal to ``0``, the standard deviation is ``NaN``. + - If ``x_i`` is ``NaN``, the standard deviation is ``NaN`` (i.e., ``NaN`` values propagate). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which standard deviations must be computed. By default, the standard deviation must be computed over the entire array. If a tuple of integers, standard deviations must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the standard deviation according to ``N-c`` where ``N`` corresponds to the total number of elements over which the standard deviation is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the standard deviation of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the corrected sample standard deviation, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. + """ + +def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + """ + Calculates the sum of the input array ``x``. + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the sum is ``NaN`` (i.e., ``NaN`` values propagate). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. + dtype: Optional[dtype] + data type of the returned array. If ``None``, + + - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + - if ``x`` has a floating-point data type, the returned array must have the default floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + + .. note:: + keyword argument is intended to help prevent data type overflows. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. + """ + +def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + """ + Calculates the variance of the input array ``x``. + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the variance. + + - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. + - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which variances must be computed. By default, the variance must be computed over the entire array. If a tuple of integers, variances must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the variance according to ``N-c`` where ``N`` corresponds to the total number of elements over which the variance is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the variance of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the unbiased sample variance, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the same data type as ``x``. + + + .. note:: + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. + """ + +__all__ = ['max', 'mean', 'min', 'prod', 'std', 'sum', 'var'] diff --git a/spec/API_specification/statistical_functions.md b/spec/API_specification/statistical_functions.md deleted file mode 100644 index 052cbcbbd..000000000 --- a/spec/API_specification/statistical_functions.md +++ /dev/null @@ -1,302 +0,0 @@ -# Statistical Functions - -> Array API specification for statistical functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -## Objects in API - - - -(function-max)= -### max(x, /, *, axis=None, keepdims=False) - -Calculates the maximum value of the input array `x`. - -```{note} -When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the minimum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `-infinity`). -``` - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the maximum value is `NaN` (i.e., `NaN` values propagate). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as `x`. - -(function-mean)= -### mean(x, /, *, axis=None, keepdims=False) - -Calculates the arithmetic mean of the input array `x`. - -#### Special Cases - -Let `N` equal the number of elements over which to compute the arithmetic mean. - -- If `N` is `0`, the arithmetic mean is `NaN`. -- If `x_i` is `NaN`, the arithmetic mean is `NaN` (i.e., `NaN` values propagate). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as `x`. - - ```{note} - While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array `x` has an integer data type, the returned array must have the default floating-point data type. - ``` - -(function-min)= -### min(x, /, *, axis=None, keepdims=False) - -Calculates the minimum value of the input array `x`. - -```{note} -When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if `x` is a floating-point input array, return `NaN`), or return the maximum possible value for the input array `x` data type (e.g., if `x` is a floating-point array, return `+infinity`). -``` - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the minimum value is `NaN` (i.e., `NaN` values propagate). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as `x`. - -(function-prod)= -### prod(x, /, *, axis=None, dtype=None, keepdims=False) - -Calculates the product of input array `x` elements. - -#### Special Cases - -Let `N` equal the number of elements over which to compute the product. - -- If `N` is `0`, the product is `1` (i.e., the empty product). - -For floating-point operands, - -- If `x_i` is `NaN`, the product is `NaN` (i.e., `NaN` values propagate). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: `None`. - -- **dtype**: _Optional\[ <dtype> ]_ - - - data type of the returned array. If `None`, - - - if the default data type corresponding to the data type "kind" (integer or floating-point) of `x` has a smaller range of values than the data type of `x` (e.g., `x` has data type `int64` and the default data type is `int32`, or `x` has data type `uint64` and the default data type is `int64`), the returned array must have the same data type as `x`. - - if `x` has a floating-point data type, the returned array must have the default floating-point data type. - - if `x` has a signed integer data type (e.g., `int16`), the returned array must have the default integer data type. - - if `x` has an unsigned integer data type (e.g., `uint16`), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is `int32`, the returned array must have a `uint32` data type). - - If the data type (either specified or resolved) differs from the data type of `x`, the input array should be cast to the specified data type before computing the product. Default: `None`. - - ```{note} - This keyword argument is intended to help prevent data type overflows. - ``` - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the `dtype` parameter above. - -(function-std)= -### std(x, /, *, axis=None, correction=0.0, keepdims=False) - -Calculates the standard deviation of the input array `x`. - -#### Special Cases - -Let `N` equal the number of elements over which to compute the standard deviation. - -- If `N - correction` is less than or equal to `0`, the standard deviation is `NaN`. -- If `x_i` is `NaN`, the standard deviation is `NaN` (i.e., `NaN` values propagate). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which standard deviations must be computed. By default, the standard deviation must be computed over the entire array. If a tuple of integers, standard deviations must be computed over multiple axes. Default: `None`. - -- **correction**: _Union\[ int, float ]_ - - - degrees of freedom adjustment. Setting this parameter to a value other than `0` has the effect of adjusting the divisor during the calculation of the standard deviation according to `N-c` where `N` corresponds to the total number of elements over which the standard deviation is computed and `c` corresponds to the provided degrees of freedom adjustment. When computing the standard deviation of a population, setting this parameter to `0` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the corrected sample standard deviation, setting this parameter to `1` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: `0`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as `x`. - - ```{note} - While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array `x` has an integer data type, the returned array must have the default floating-point data type. - ``` - -(function-sum)= -### sum(x, /, *, axis=None, dtype=None, keepdims=False) - -Calculates the sum of the input array `x`. - -#### Special Cases - -Let `N` equal the number of elements over which to compute the sum. - -- If `N` is `0`, the sum is `0` (i.e., the empty sum). - -For floating-point operands, - -- If `x_i` is `NaN`, the sum is `NaN` (i.e., `NaN` values propagate). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: `None`. - -- **dtype**: _Optional\[ <dtype> ]_ - - - data type of the returned array. If `None`, - - - if the default data type corresponding to the data type "kind" (integer or floating-point) of `x` has a smaller range of values than the data type of `x` (e.g., `x` has data type `int64` and the default data type is `int32`, or `x` has data type `uint64` and the default data type is `int64`), the returned array must have the same data type as `x`. - - if `x` has a floating-point data type, the returned array must have the default floating-point data type. - - if `x` has a signed integer data type (e.g., `int16`), the returned array must have the default integer data type. - - if `x` has an unsigned integer data type (e.g., `uint16`), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is `int32`, the returned array must have a `uint32` data type). - - If the data type (either specified or resolved) differs from the data type of `x`, the input array should be cast to the specified data type before computing the sum. Default: `None`. - - ```{note} - This keyword argument is intended to help prevent data type overflows. - ``` - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the `dtype` parameter above. - -(function-var)= -### var(x, /, *, axis=None, correction=0.0, keepdims=False) - -Calculates the variance of the input array `x`. - -#### Special Cases - -Let `N` equal the number of elements over which to compute the variance. - -- If `N - correction` is less than or equal to `0`, the variance is `NaN`. -- If `x_i` is `NaN`, the variance is `NaN` (i.e., `NaN` values propagate). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis or axes along which variances must be computed. By default, the variance must be computed over the entire array. If a tuple of integers, variances must be computed over multiple axes. Default: `None`. - -- **correction**: _Union\[ int, float ]_ - - - degrees of freedom adjustment. Setting this parameter to a value other than `0` has the effect of adjusting the divisor during the calculation of the variance according to `N-c` where `N` corresponds to the total number of elements over which the variance is computed and `c` corresponds to the provided degrees of freedom adjustment. When computing the variance of a population, setting this parameter to `0` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the unbiased sample variance, setting this parameter to `1` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: `0`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the same data type as `x`. - - ```{note} - While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array `x` has an integer data type, the returned array must have the default floating-point data type. - ``` diff --git a/spec/API_specification/statistical_functions.rst b/spec/API_specification/statistical_functions.rst new file mode 100644 index 000000000..68e6830e2 --- /dev/null +++ b/spec/API_specification/statistical_functions.rst @@ -0,0 +1,32 @@ +Statistical Functions +===================== + + Array API specification for statistical functions. + +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`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. + +Objects in API +-------------- + +.. currentmodule:: signatures.statistical_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + + max + mean + min + prod + std + sum + var From 36c6b7500db59355bfbed3136d1b1a7c1156d5f3 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 31 Jan 2022 03:51:43 -0500 Subject: [PATCH 177/551] PR: Transform set functions md to rst (#369) * Transform set functions md to rst * Update note directives --- spec/API_specification/set_functions.md | 168 ------------------ spec/API_specification/set_functions.rst | 26 +++ .../signatures/set_functions.py | 139 +++++++++++++++ 3 files changed, 165 insertions(+), 168 deletions(-) delete mode 100644 spec/API_specification/set_functions.md create mode 100644 spec/API_specification/set_functions.rst create mode 100644 spec/API_specification/signatures/set_functions.py diff --git a/spec/API_specification/set_functions.md b/spec/API_specification/set_functions.md deleted file mode 100644 index efffef125..000000000 --- a/spec/API_specification/set_functions.md +++ /dev/null @@ -1,168 +0,0 @@ -# Set Functions - -> Array API specification for creating and operating on sets. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) arguments. -- Unless stated otherwise, functions must support the data types defined in {ref}`data-types`. - -## Objects in API - - - -(function-unique-all)= -### unique_all(x, /) - -:::{admonition} Data-dependent output shape -:class: important - -The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. -::: - -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`. - -```{note} -Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. - -- As `nan` values compare as `False`, `nan` values should be considered distinct. -- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). - -As signed zeros are not distinct, using `inverse_indices` to reconstruct the input array is not guaranteed to return an array having the exact same values. - -Each `nan` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. - -#### Returns - -- **out**: _Tuple\[ <array>, <array>, <array>, <array> ]_ - - - a namedtuple `(values, indices, inverse_indices, counts)` whose - - - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. - - second element must have the field name `indices` and must be an array containing the indices (first occurrences) of `x` that result in `values`. The array must have the same shape as `values` and must have the default array index data type. - - third element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and must have the default array index data type. - - fourth element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default array index data type. - - ```{note} - The order of unique elements is not specified and may vary between implementations. - ``` - -(function-unique-counts)= -### unique_counts(x, /) - -:::{admonition} Data-dependent output shape -:class: important - -The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. -::: - -Returns the unique elements of an input array `x` and the corresponding counts for each unique element in `x`. - -```{note} -Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. - -- As `nan` values compare as `False`, `nan` values should be considered distinct. -- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). - -Each `nan` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. - -#### Returns - -- **out**: _Tuple\[ <array>, <array> ]_ - - - a namedtuple `(values, counts)` whose - - - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. - - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in `x`. The returned array must have same shape as `values` and must have the default array index data type. - - ```{note} - The order of unique elements is not specified and may vary between implementations. - ``` - -(function-unique-inverse)= -### unique_inverse(x, /) - -:::{admonition} Data-dependent output shape -:class: important - -The shape of one of the output arrays for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. -::: - -Returns the unique elements of an input array `x` and the indices from the set of unique elements that reconstruct `x`. - -```{note} -Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. - -- As `nan` values compare as `False`, `nan` values should be considered distinct. -- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). - -As signed zeros are not distinct, using `inverse_indices` to reconstruct the input array is not guaranteed to return an array having the exact same values. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. - -#### Returns - -- **out**: _Tuple\[ <array>, <array> ]_ - - - a namedtuple `(values, inverse_indices)` whose - - - first element must have the field name `values` and must be an array containing the unique elements of `x`. The array must have the same data type as `x`. - - second element must have the field name `inverse_indices` and must be an array containing the indices of `values` that reconstruct `x`. The array must have the same shape as `x` and have the default array index data type. - - ```{note} - The order of unique elements is not specified and may vary between implementations. - ``` - -(function-unique-values)= -### unique_values(x, /) - -:::{admonition} Data-dependent output shape -:class: important - -The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. -::: - -Returns the unique elements of an input array `x`. - -```{note} -Uniqueness should be determined based on value equality (i.e., `x_i == x_j`). For input arrays having floating-point data types, value-based equality implies the following behavior. - -- As `nan` values compare as `False`, `nan` values should be considered distinct. -- As `-0` and `+0` compare as `True`, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return `-0` if `-0` occurs before `+0`). -``` - -#### Parameters - -- **x**: _<array>_ - - - input array. If `x` has more than one dimension, the function must flatten `x` and return the unique elements of the flattened array. - -#### Returns - -- **out**: _<array>_ - - - an array containing the set of unique elements in `x`. The returned array must have the same data type as `x`. - - ```{note} - The order of unique elements is not specified and may vary between implementations. - ``` diff --git a/spec/API_specification/set_functions.rst b/spec/API_specification/set_functions.rst new file mode 100644 index 000000000..1f287fece --- /dev/null +++ b/spec/API_specification/set_functions.rst @@ -0,0 +1,26 @@ +Set Functions +============= + + Array API specification for creating and operating on sets. + +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. +- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. + +Objects in API +-------------- + +.. currentmodule:: signatures.set_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + + unique_all + unique_counts + unique_inverse + unique_values diff --git a/spec/API_specification/signatures/set_functions.py b/spec/API_specification/signatures/set_functions.py new file mode 100644 index 000000000..bd24e5323 --- /dev/null +++ b/spec/API_specification/signatures/set_functions.py @@ -0,0 +1,139 @@ +from ._types import Tuple, array + +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``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Each ``nan`` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array, array, array] + a namedtuple ``(values, indices, inverse_indices, counts)`` whose + + - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. + - third element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and must have the default array index data type. + - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + """ + +def unique_counts(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Each ``nan`` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple `(values, counts)` whose + + - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + """ + +def unique_inverse(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(values, inverse_indices)`` whose + + - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + """ + +def unique_values(x: array, /) -> array: + """ + Returns the unique elements of an input array ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + + - As ``nan`` values compare as ``False``, ``nan`` values should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: array + an array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + """ + +__all__ = ['unique_all', 'unique_counts', 'unique_inverse', 'unique_values'] \ No newline at end of file From 533e6933bf0e3e95385351b802d37fad646ab150 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 31 Jan 2022 03:56:45 -0500 Subject: [PATCH 178/551] PR: Transform searching functions md to rst (#368) * Transform searching functions md to rst * Fix typo * Lowercase first sentence to ensure consistency with rest of spec This commit addresses an oversight in the specification prior to Markdown to rST conversion. Co-authored-by: Athan --- spec/API_specification/searching_functions.md | 115 ------------------ .../API_specification/searching_functions.rst | 30 +++++ .../signatures/searching_functions.py | 80 ++++++++++++ 3 files changed, 110 insertions(+), 115 deletions(-) delete mode 100644 spec/API_specification/searching_functions.md create mode 100644 spec/API_specification/searching_functions.rst create mode 100644 spec/API_specification/signatures/searching_functions.py diff --git a/spec/API_specification/searching_functions.md b/spec/API_specification/searching_functions.md deleted file mode 100644 index 7bf3f346e..000000000 --- a/spec/API_specification/searching_functions.md +++ /dev/null @@ -1,115 +0,0 @@ -(searching-functions)= - -# Searching Functions - -> Array API specification for functions for searching 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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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 - - - -(function-argmax)= -### argmax(x, /, *, axis=None, keepdims=False) - -Returns the indices of the maximum values along a specified axis. When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -- **axis**: _Optional\[ int ]_ - - - axis along which to search. If `None`, the function must return the index of the maximum value of the flattened array. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if `axis` is `None`, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. - -(function-argmin)= -### argmin(x, /, *, axis=None, keepdims=False) - -Returns the indices of the minimum values along a specified axis. When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -- **axis**: _Optional\[ int ]_ - - - axis along which to search. If `None`, the function must return the index of the minimum value of the flattened array. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the reduced axes (dimensions) must not be included in the result. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - if `axis` is `None`, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. - -(function-nonzero)= -### nonzero(x, /) - -:::{admonition} Data-dependent output shape -:class: important - -The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See {ref}`data-dependent-output-shapes` section for more details. -::: - -Returns the indices of the array elements which are non-zero. - -#### Parameters - -- **x**: _<array>_ - - - input array. Must have a positive rank. If `x` is zero-dimensional, the function must raise an exception. - -#### Returns - -- **out**: _Tuple\[ <array>, ... ]_ - - - a tuple of `k` arrays, one for each dimension of `x` and each of size `n` (where `n` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. - -(function-where)= -### where(condition, x1, x2, /) - -Returns elements chosen from `x1` or `x2` depending on `condition`. - -#### Parameters - -- **condition**: _<array>_ - - - when `True`, yield `x1_i`; otherwise, yield `x2_i`. Must be compatible with `x1` and `x2` (see {ref}`broadcasting`). - -- **x1**: _<array>_ - - - first input array. Must be compatible with `condition` and `x2` (see {ref}`broadcasting`). - -- **x2**: _<array>_ - - - second input array. Must be compatible with `condition` and `x1` (see {ref}`broadcasting`). - -#### Returns - -- **out**: _<array>_ - - - an array with elements from `x1` where `condition` is `True`, and elements from `x2` elsewhere. The returned array must have a data type determined by {ref}`type-promotion` rules with the arrays `x1` and `x2`. diff --git a/spec/API_specification/searching_functions.rst b/spec/API_specification/searching_functions.rst new file mode 100644 index 000000000..18289466a --- /dev/null +++ b/spec/API_specification/searching_functions.rst @@ -0,0 +1,30 @@ +.. _searching-functions: + +Searching Functions +=================== + + Array API specification for functions for searching 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.searching_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + + argmax + argmin + nonzero + where diff --git a/spec/API_specification/signatures/searching_functions.py b/spec/API_specification/signatures/searching_functions.py new file mode 100644 index 000000000..c2875adcc --- /dev/null +++ b/spec/API_specification/signatures/searching_functions.py @@ -0,0 +1,80 @@ +from ._types import Optional, Tuple, array + +def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the maximum values along a specified axis. When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the maximum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. + """ + +def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the minimum values along a specified axis. When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the minimum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. + """ + +def nonzero(x: array, /) -> Tuple[array, ...]: + """ + Returns the indices of the array elements which are non-zero. + + .. admonition:: Data-dependent output shape + :class: admonition important + + The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array. Must have a positive rank. If ``x`` is zero-dimensional, the function must raise an exception. + + Returns + ------- + out: Typle[array, ...] + a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + """ + +def where(condition: array, x1: array, x2: array, /) -> array: + """ + Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. + + Parameters + ---------- + condition: array + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + x1: array + first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). + x2: array + second input array. Must be compatible with ``condition`` and ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. + """ + +__all__ = ['argmax', 'argmin', 'nonzero', 'where'] From 28634c21acbe13673004022f3a7f1125cbd395c3 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 31 Jan 2022 03:58:58 -0500 Subject: [PATCH 179/551] PR: Transform manipulation_functions.md to rst (#354) * Transform manipulation_functions.md to rst * Update note directives --- .../manipulation_functions.md | 195 ------------------ .../manipulation_functions.rst | 31 +++ .../signatures/manipulation_functions.py | 147 +++++++++++++ 3 files changed, 178 insertions(+), 195 deletions(-) delete mode 100644 spec/API_specification/manipulation_functions.md create mode 100644 spec/API_specification/manipulation_functions.rst create mode 100644 spec/API_specification/signatures/manipulation_functions.py diff --git a/spec/API_specification/manipulation_functions.md b/spec/API_specification/manipulation_functions.md deleted file mode 100644 index 36f59b4c7..000000000 --- a/spec/API_specification/manipulation_functions.md +++ /dev/null @@ -1,195 +0,0 @@ -# Manipulation Functions - -> Array API specification for manipulating 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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) arguments. -- Unless stated otherwise, functions must adhere to the type promotion rules defined in {ref}`type-promotion`. - -## Objects in API - - - -(function-concat)= -### concat(arrays, /, *, axis=0) - -Joins a sequence of arrays along an existing axis. - -#### Parameters - -- **arrays**: _Union\[Tuple\[ <array>, ... ], List\[ <array> ] ]_ - - - input arrays to join. The arrays must have the same shape, except in the dimension specified by `axis`. - -- **axis**: _Optional\[ int ]_ - - - axis along which the arrays will be joined. If `axis` is `None`, arrays must be flattened before concatenation. If `axis` is negative, the function must determine the axis along which to join by counting from the last dimension. Default: `0`. - -#### Returns - -- **out**: _<array>_ - - - an output array containing the concatenated values. If the input arrays have different data types, normal [type promotion rules](type_promotion.md) must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. - - ```{note} - - This specification leaves type promotion between data type families (i.e., `intxx` and `floatxx`) unspecified. - ``` - -(function-expand_dims)= -### expand_dims(x, /, axis) - -Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by `axis`. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axis**: _int_ - - - axis position. Must follow Python's indexing rules: zero-based and negative indices must be counted backward from the last dimension. If `x` has rank `N`, a valid `axis` must reside on the interval `[-N-1, N+1]`. An `IndexError` exception must be raised if provided an invalid `axis` position. - -#### Returns - -- **out**: _<array>_ - - - an expanded output array having the same data type as `x`. - -(function-flip)= -### flip(x, /, *, axis=None) - -Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis (or axes) along which to flip. If `axis` is `None`, the function must flip all input array axes. If `axis` is negative, the function must count from the last dimension. If provided more than one axis, the function must flip only the specified axes. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an output array having the same data type and shape as `x` and whose elements, relative to `x`, are reordered. - -(function-permute-dims)= -### permute_dims(x, /, axes) - -Permutes the axes (dimensions) of an array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axes**: _Tuple\[ int, ... ]_ - - - tuple containing a permutation of `(0, 1, ..., N-1)` where `N` is the number of axes (dimensions) of `x`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the axes permutation. The returned array must have the same data type as `x`. - -(function-reshape)= -### reshape(x, /, shape) - -Reshapes an array without changing its data. - -#### Parameters - -- **x**: _<array>_ - - - input array to reshape. - -- **shape**: _Tuple\[ int, ... ]_ - - - a new shape compatible with the original shape. One shape dimension is allowed to be `-1`. When a shape dimension is `-1`, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. - -#### Returns - -- **out**: _<array>_ - - - an output array having the same data type, elements, and underlying element order as `x`. - -(function-roll)= -### roll(x, /, shift, *, axis=None) - -Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **shift**: _Union\[ int, Tuple\[ int, ... ] ]_ - - - number of places by which the elements are shifted. If `shift` is a tuple, then `axis` must be a tuple of the same size, and each of the given axes must be shifted by the corresponding element in `shift`. If `shift` is an `int` and `axis` a tuple, then the same `shift` must be used for all specified axes. If a shift is positive, then array elements must be shifted positively (toward larger indices) along the dimension of `axis`. If a shift is negative, then array elements must be shifted negatively (toward smaller indices) along the dimension of `axis`. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - axis (or axes) along which elements to shift. If `axis` is `None`, the array must be flattened, shifted, and then restored to its original shape. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an output array having the same data type as `x` and whose elements, relative to `x`, are shifted. - -(function-squeeze)= -### squeeze(x, /, axis) - -Removes singleton dimensions (axes) from `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. - -- **axis**: _Union\[ int, Tuple\[ int, ... ] ]_ - - - axis (or axes) to squeeze. If a specified axis has a size greater than one, a `ValueError` must be raised. - -#### Returns - -- **out**: _<array>_ - - - an output array having the same data type and elements as `x`. - -(function-stack)= -### stack(arrays, /, *, axis=0) - -Joins a sequence of arrays along a new axis. - -#### Parameters - -- **arrays**: _Union\[Tuple\[ <array>, ... ], List\[ <array> ] ]_ - - - input arrays to join. Each array must have the same shape. - -- **axis**: _int_ - - - axis along which the arrays will be joined. Providing an `axis` specifies the index of the new axis in the dimensions of the result. For example, if `axis` is `0`, the new axis will be the first dimension and the output array will have shape `(N, A, B, C)`; if `axis` is `1`, the new axis will be the second dimension and the output array will have shape `(A, N, B, C)`; and, if `axis` is `-1`, the new axis will be the last dimension and the output array will have shape `(A, B, C, N)`. A valid `axis` must be on the interval `[-N, N)`, where `N` is the rank (number of dimensions) of `x`. If provided an `axis` outside of the required interval, the function must raise an exception. Default: `0`. - -#### Returns - -- **out**: _<array>_ - - - an output array having rank `N+1`, where `N` is the rank (number of dimensions) of `x`. If the input arrays have different data types, normal [type promotion rules](type_promotion.md) must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. - - ```{note} - - This specification leaves type promotion between data type families (i.e., `intxx` and `floatxx`) unspecified. - ``` diff --git a/spec/API_specification/manipulation_functions.rst b/spec/API_specification/manipulation_functions.rst new file mode 100644 index 000000000..f2fcbccc5 --- /dev/null +++ b/spec/API_specification/manipulation_functions.rst @@ -0,0 +1,31 @@ +Manipulation Functions +====================== + + Array API specification for manipulating 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. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. + +Objects in API +-------------- + +.. currentmodule:: signatures.manipulation_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + concat + expand_dims + flip + permute_dims + reshape + roll + squeeze + stack diff --git a/spec/API_specification/signatures/manipulation_functions.py b/spec/API_specification/signatures/manipulation_functions.py new file mode 100644 index 000000000..35e79e9d3 --- /dev/null +++ b/spec/API_specification/signatures/manipulation_functions.py @@ -0,0 +1,147 @@ +from ._types import List, Optional, Tuple, Union, array + +def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0) -> array: + """ + Joins a sequence of arrays along an existing axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. The arrays must have the same shape, except in the dimension specified by ``axis``. + axis: Optional[int] + axis along which the arrays will be joined. If ``axis`` is ``None``, arrays must be flattened before concatenation. If ``axis`` is negative, the function must determine the axis along which to join by counting from the last dimension. Default: ``0``. + + Returns + ------- + out: array + an output array containing the concatenated values. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + +def expand_dims(x: array, /, *, axis: int = 0) -> array: + """ + Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. + + Parameters + ---------- + x: array + input array. + axis: int + axis position. Must follow Python's indexing rules: zero-based and negative indices must be counted backward from the last dimension. If ``x`` has rank ``N``, a valid ``axis`` must reside on the interval ``[-N-1, N+1]``. An ``IndexError`` exception must be raised if provided an invalid ``axis`` position. + + Returns + ------- + out: array + an expanded output array having the same data type as ``x``. + """ + +def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + """ + Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which to flip. If ``axis`` is ``None``, the function must flip all input array axes. If ``axis`` is negative, the function must count from the last dimension. If provided more than one axis, the function must flip only the specified axes. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. + """ + +def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: + """ + Permutes the axes (dimensions) of an array ``x``. + + Parameters + ---------- + x: array + input array. + axes: Tuple[int, ...] + tuple containing a permutation of ``(0, 1, ..., N-1)`` where ``N`` is the number of axes (dimensions) of ``x``. + + Returns + ------- + out: array + an array containing the axes permutation. The returned array must have the same data type as ``x``. + """ + +def reshape(x: array, /, shape: Tuple[int, ...]) -> array: + """ + Reshapes an array without changing its data. + + Parameters + ---------- + x: array + input array to reshape. + shape: Tuple[int, ...] + a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. + + Returns + ------- + out: array + an output array having the same data type, elements, and underlying element order as ``x``. + """ + +def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + """ + Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. + + Parameters + ---------- + x: array + input array. + shift: Union[int, Tuple[int, ...]] + number of places by which the elements are shifted. If ``shift`` is a tuple, then ``axis`` must be a tuple of the same size, and each of the given axes must be shifted by the corresponding element in ``shift``. If ``shift`` is an ``int`` and ``axis`` a tuple, then the same ``shift`` must be used for all specified axes. If a shift is positive, then array elements must be shifted positively (toward larger indices) along the dimension of ``axis``. If a shift is negative, then array elements must be shifted negatively (toward smaller indices) along the dimension of ``axis``. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which elements to shift. If ``axis`` is ``None``, the array must be flattened, shifted, and then restored to its original shape. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. + """ + +def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: + """ + Removes singleton dimensions (axes) from ``x``. + + Parameters + ---------- + x: array + input array. + axis: Union[int, Tuple[int, ...]] + axis (or axes) to squeeze. If a specified axis has a size greater than one, a ``ValueError`` must be raised. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + """ + +def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: + """ + Joins a sequence of arrays along a new axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. Each array must have the same shape. + axis: int + axis along which the arrays will be joined. Providing an ``axis`` specifies the index of the new axis in the dimensions of the result. For example, if ``axis`` is ``0``, the new axis will be the first dimension and the output array will have shape ``(N, A, B, C)``; if ``axis`` is ``1``, the new axis will be the second dimension and the output array will have shape ``(A, N, B, C)``; and, if ``axis`` is ``-1``, the new axis will be the last dimension and the output array will have shape ``(A, B, C, N)``. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + -------- + out: array + an output array having rank ``N+1``, where ``N`` is the rank (number of dimensions) of ``x``. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + +__all__ = ['concat', 'expand_dims', 'flip', 'permute_dims', 'reshape', 'roll', 'squeeze', 'stack'] \ No newline at end of file From 0beb81b86f72221abf1bfec378ce374e2ff0ae9d Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 31 Jan 2022 04:10:44 -0500 Subject: [PATCH 180/551] Transform elementwise_functions.md to rst (#351) * Transform elementwise_functions.md to rst * Fix rendering * Update note directives * Fix non existent labels * Add missing blank line Co-authored-by: Athan --- .../elementwise_functions.md | 1556 ----------------- .../elementwise_functions.rst | 86 + .../signatures/array_object.py | 44 +- .../signatures/elementwise_functions.py | 1361 ++++++++++++++ 4 files changed, 1469 insertions(+), 1578 deletions(-) delete mode 100644 spec/API_specification/elementwise_functions.md create mode 100644 spec/API_specification/elementwise_functions.rst create mode 100644 spec/API_specification/signatures/elementwise_functions.py diff --git a/spec/API_specification/elementwise_functions.md b/spec/API_specification/elementwise_functions.md deleted file mode 100644 index 9602f5f7c..000000000 --- a/spec/API_specification/elementwise_functions.md +++ /dev/null @@ -1,1556 +0,0 @@ -(element-wise-functions)= - -# Element-wise Functions - -> Array API specification for element-wise functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. -- Functions may only be required for a subset of input data type. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See {ref}`data-type-categories`. -- Unless stated otherwise, functions must adhere to the type promotion rules defined in {ref}`type-promotion`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. -- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in {ref}`accuracy`. - -## Objects in API - - - -(function-abs)= -### abs(x, /) - -Calculates the absolute value for each element `x_i` of the input array `x` (i.e., the element-wise result has the same magnitude as the respective element in `x` but has positive sign). - -```{note} -For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. -``` - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `-0`, the result is `+0`. -- If `x_i` is `-infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the absolute value of each element in `x`. The returned array must have the same data type as `x`. - -(function-acos)= -### acos(x, /) - -Calculates an implementation-dependent approximation of the principal value of the inverse cosine, having domain `[-1, +1]` and codomain `[+0, +π]`, for each element `x_i` of the input array `x`. Each element-wise result is expressed in radians. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is greater than `1`, the result is `NaN`. -- If `x_i` is less than `-1`, the result is `NaN`. -- If `x_i` is `1`, the result is `+0`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the inverse cosine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-acosh)= -### acosh(x, /) - -Calculates an implementation-dependent approximation to the inverse hyperbolic cosine, having domain `[+1, +infinity]` and codomain `[+0, +infinity]`, for each element `x_i` of the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is less than `1`, the result is `NaN`. -- If `x_i` is `1`, the result is `+0`. -- If `x_i` is `+infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the inverse hyperbolic cosine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-add)= -### add(x1, x2, /) - -Calculates the sum for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Special Cases - -For floating-point operands, - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is `+infinity` and `x2_i` is `-infinity`, the result is `NaN`. -- If `x1_i` is `-infinity` and `x2_i` is `+infinity`, the result is `NaN`. -- If `x1_i` is `+infinity` and `x2_i` is `+infinity`, the result is `+infinity`. -- If `x1_i` is `-infinity` and `x2_i` is `-infinity`, the result is `-infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a finite number, the result is `+infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a finite number, the result is `-infinity`. -- If `x1_i` is a finite number and `x2_i` is `+infinity`, the result is `+infinity`. -- If `x1_i` is a finite number and `x2_i` is `-infinity`, the result is `-infinity`. -- If `x1_i` is `-0` and `x2_i` is `-0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is `+0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `-0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `+0`, the result is `+0`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is a nonzero finite number, the result is `x2_i`. -- If `x1_i` is a nonzero finite number and `x2_i` is either `+0` or `-0`, the result is `x1_i`. -- If `x1_i` is a nonzero finite number and `x2_i` is `-x1_i`, the result is `+0`. -- In the remaining cases, when neither `infinity`, `+0`, `-0`, nor a `NaN` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. - -```{note} -Floating-point addition is a commutative operation, but not always associative. -``` - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise sums. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-asin)= -### asin(x, /) - -Calculates an implementation-dependent approximation of the principal value of the inverse sine, having domain `[-1, +1]` and codomain `[-π/2, +π/2]` for each element `x_i` of the input array `x`. Each element-wise result is expressed in radians. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is greater than `1`, the result is `NaN`. -- If `x_i` is less than `-1`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the inverse sine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-asinh)= -### asinh(x, /) - -Calculates an implementation-dependent approximation to the inverse hyperbolic sine, having domain `[-infinity, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` in the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `-infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the inverse hyperbolic sine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-atan)= -### atan(x, /) - -Calculates an implementation-dependent approximation of the principal value of the inverse tangent, having domain `[-infinity, +infinity]` and codomain `[-π/2, +π/2]`, for each element `x_i` of the input array `x`. Each element-wise result is expressed in radians. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `+infinity`, the result is an implementation-dependent approximation to `+π/2`. -- If `x_i` is `-infinity`, the result is an implementation-dependent approximation to `-π/2`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the inverse tangent of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-atan2)= -### atan2(x1, x2, /) - -Calculates an implementation-dependent approximation of the inverse tangent of the quotient `x1/x2`, having domain `[-infinity, +infinity] x [-infinity, +infinity]` (where the `x` notation denotes the set of ordered pairs of elements `(x1_i, x2_i)`) and codomain `[-π, +π]`, for each pair of elements `(x1_i, x2_i)` of the input arrays `x1` and `x2`, respectively. Each element-wise result is expressed in radians. - -The mathematical signs of `x1_i` and `x2_i` determine the quadrant of each element-wise result. The quadrant (i.e., branch) is chosen such that each element-wise result is the signed angle in radians between the ray ending at the origin and passing through the point `(1,0)` and the ray ending at the origin and passing through the point `(x2_i, x1_i)`. - -```{note} -Note the role reversal: the "y-coordinate" is the first function parameter; the "x-coordinate" is the second function parameter. The parameter order is intentional and traditional for the two-argument inverse tangent function where the y-coordinate argument is first and the x-coordinate argument is second. -``` - -By IEEE 754 convention, the inverse tangent of the quotient `x1/x2` is defined for `x2_i` equal to positive or negative zero and for either or both of `x1_i` and `x2_i` equal to positive or negative `infinity`. - -#### Special Cases - -For floating-point operands, - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is an implementation-dependent approximation to `+π/2`. -- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is an implementation-dependent approximation to `+π/2`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `+0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is `-0`, the result is an implementation-dependent approximation to `+π`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is an implementation-dependent approximation to `+π`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is `+0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is `-0`, the result is an implementation-dependent approximation to `-π`. -- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is an implementation-dependent approximation to `-π`. -- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is an implementation-dependent approximation to `-π/2`. -- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is an implementation-dependent approximation to `-π/2`. -- If `x1_i` is greater than `0`, `x1_i` is a finite number, and `x2_i` is `+infinity`, the result is `+0`. -- If `x1_i` is greater than `0`, `x1_i` is a finite number, and `x2_i` is `-infinity`, the result is an implementation-dependent approximation to `+π`. -- If `x1_i` is less than `0`, `x1_i` is a finite number, and `x2_i` is `+infinity`, the result is `-0`. -- If `x1_i` is less than `0`, `x1_i` is a finite number, and `x2_i` is `-infinity`, the result is an implementation-dependent approximation to `-π`. -- If `x1_i` is `+infinity` and `x2_i` is finite, the result is an implementation-dependent approximation to `+π/2`. -- If `x1_i` is `-infinity` and `x2_i` is finite, the result is an implementation-dependent approximation to `-π/2`. -- If `x1_i` is `+infinity` and `x2_i` is `+infinity`, the result is an implementation-dependent approximation to `+π/4`. -- If `x1_i` is `+infinity` and `x2_i` is `-infinity`, the result is an implementation-dependent approximation to `+3π/4`. -- If `x1_i` is `-infinity` and `x2_i` is `+infinity`, the result is an implementation-dependent approximation to `-π/4`. -- If `x1_i` is `-infinity` and `x2_i` is `-infinity`, the result is an implementation-dependent approximation to `-3π/4`. - -#### Parameters - -- **x1**: _<array>_ - - - input array corresponding to the y-coordinates. Should have a floating-point data type. - -- **x2**: _<array>_ - - - input array corresponding to the x-coordinates. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the inverse tangent of the quotient `x1/x2`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-atanh)= -### atanh(x, /) - -Calculates an implementation-dependent approximation to the inverse hyperbolic tangent, having domain `[-1, +1]` and codomain `[-infinity, +infinity]`, for each element `x_i` of the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is less than `-1`, the result is `NaN`. -- If `x_i` is greater than `1`, the result is `NaN`. -- If `x_i` is `-1`, the result is `-infinity`. -- If `x_i` is `+1`, the result is `+infinity`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the inverse hyperbolic tangent of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-bitwise_and)= -### bitwise_and(x1, x2, /) - -Computes the bitwise AND of the underlying binary representation of each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have an integer or boolean data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-bitwise_left_shift)= -### bitwise_left_shift(x1, x2, /) - -Shifts the bits of each element `x1_i` of the input array `x1` to the left by appending `x2_i` (i.e., the respective element in the input array `x2`) zeros to the right of `x1_i`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have an integer data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have an integer data type. Each element must be greater than or equal to `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-bitwise_invert)= -### bitwise_invert(x, /) - -Inverts (flips) each bit for each element `x_i` of the input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have the same data type as `x`. - -(function-bitwise_or)= -### bitwise_or(x1, x2, /) - -Computes the bitwise OR of the underlying binary representation of each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have an integer or boolean data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-bitwise_right_shift)= -### bitwise_right_shift(x1, x2, /) - -Shifts the bits of each element `x1_i` of the input array `x1` to the right according to the respective element `x2_i` of the input array `x2`. - -```{note} -This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. -``` - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have an integer data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have an integer data type. Each element must be greater than or equal to `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-bitwise_xor)= -### bitwise_xor(x1, x2, /) - -Computes the bitwise XOR of the underlying binary representation of each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have an integer or boolean data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have an integer or boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-ceil)= -### ceil(x, /) - -Rounds each element `x_i` of the input array `x` to the smallest (i.e., closest to `-infinity`) integer-valued number that is not less than `x_i`. - -#### Special Cases - -- If `x_i` is already integer-valued, the result is `x_i`. - -For floating-point operands, - -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `-infinity`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `NaN`, the result is `NaN`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the rounded result for each element in `x`. The returned array must have the same data type as `x`. - -(function-cos)= -### cos(x, /) - -Calculates an implementation-dependent approximation to the cosine, having domain `(-infinity, +infinity)` and codomain `[-1, +1]`, for each element `x_i` of the input array `x`. Each element `x_i` is assumed to be expressed in radians. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `1`. -- If `x_i` is `-0`, the result is `1`. -- If `x_i` is `+infinity`, the result is `NaN`. -- If `x_i` is `-infinity`, the result is `NaN`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements are each expressed in radians. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the cosine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-cosh)= -### cosh(x, /) - -Calculates an implementation-dependent approximation to the hyperbolic cosine, having domain `[-infinity, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` in the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `1`. -- If `x_i` is `-0`, the result is `1`. -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the hyperbolic cosine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-divide)= -### divide(x1, x2, /) - -Calculates the division for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -```{note} -If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - -Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. -``` - -#### Special Cases - -For floating-point operands, - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. -- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. -- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. -- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. -- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - -#### Parameters - -- **x1**: _<array>_ - - - dividend input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - divisor input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-equal)= -### equal(x1, x2, /) - -Computes the truth value of `x1_i == x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. May have any data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). May have any data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-exp)= -### exp(x, /) - -Calculates an implementation-dependent approximation to the exponential function, having domain `[-infinity, +infinity]` and codomain `[+0, +infinity]`, for each element `x_i` of the input array `x` (`e` raised to the power of `x_i`, where `e` is the base of the natural logarithm). - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `1`. -- If `x_i` is `-0`, the result is `1`. -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `+0`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated exponential function result for each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-expm1)= -### expm1(x, /) - -Calculates an implementation-dependent approximation to `exp(x)-1`, having domain `[-infinity, +infinity]` and codomain `[-1, +infinity]`, for each element `x_i` of the input array `x`. - -```{note} -The purpose of this function is to calculate `exp(x)-1.0` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply `exp(x)-1.0`. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. -``` - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `-1`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-floor)= -### floor(x, /) - -Rounds each element `x_i` of the input array `x` to the greatest (i.e., closest to `+infinity`) integer-valued number that is not greater than `x_i`. - -#### Special Cases - -- If `x_i` is already integer-valued, the result is `x_i`. - -For floating-point operands, - -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `-infinity`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `NaN`, the result is `NaN`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the rounded result for each element in `x`. The returned array must have the same data type as `x`. - -(function-floor_divide)= -### floor_divide(x1, x2, /) - -Rounds the result of dividing each element `x1_i` of the input array `x1` by the respective element `x2_i` of the input array `x2` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. - -```{note} -For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. -``` - -#### Special Cases - -```{note} -Floor division was introduced in Python via [PEP 238](https://www.python.org/dev/peps/pep-0238/) with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a `float`, while the latter was computed when both operands were `int`s. Overloading the `/` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. - -To resolve this ambiguity, `/` was designated for true division, and `//` was designated for floor division. Semantically, floor division was [defined](https://www.python.org/dev/peps/pep-0238/#semantics-of-floor-division) as equivalent to `a // b == floor(a/b)`; however, special floating-point cases were left ill-defined. - -Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is `infinity`, libraries may diverge with some choosing to strictly follow `floor(a/b)` and others choosing to pair `//` with `%` according to the relation `b = a % b + b * (a // b)`. The special cases leading to divergent behavior are documented below. - -This specification prefers floor division to match `floor(divide(x1, x2))` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. -``` - -For floating-point operands, - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `-0` and `x2_i` is greater than `0`, the result is `-0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `-0`. -- If `x1_i` is `-0` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is greater than `0` and `x2_i` is `+0`, the result is `+infinity`. -- If `x1_i` is greater than `0` and `x2_i` is `-0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `+0`, the result is `-infinity`. -- If `x1_i` is less than `0` and `x2_i` is `-0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `+infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `-infinity` and `x2_i` is a positive (i.e., greater than `0`) finite number, the result is `-infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is `-infinity` and `x2_i` is a negative (i.e., less than `0`) finite number, the result is `+infinity`. (**note**: libraries may return `NaN` to match Python behavior.) -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `+infinity`, the result is `+0`. -- If `x1_i` is a positive (i.e., greater than `0`) finite number and `x2_i` is `-infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `+infinity`, the result is `-0`. (**note**: libraries may return `-1.0` to match Python behavior.) -- If `x1_i` is a negative (i.e., less than `0`) finite number and `x2_i` is `-infinity`, the result is `+0`. -- If `x1_i` and `x2_i` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. -- If `x1_i` and `x2_i` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. -- In the remaining cases, where neither `-infinity`, `+0`, `-0`, nor `NaN` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - -#### Parameters - -- **x1**: _<array>_ - - - dividend input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - divisor input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-greater)= -### greater(x1, x2, /) - -Computes the truth value of `x1_i > x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-greater_equal)= -### greater_equal(x1, x2, /) - -Computes the truth value of `x1_i >= x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-isfinite)= -### isfinite(x, /) - -Tests each element `x_i` of the input array `x` to determine if finite (i.e., not `NaN` and not equal to positive or negative infinity). - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing test results. An element `out_i` is `True` if `x_i` is finite and `False` otherwise. The returned array must have a data type of `bool`. - -(function-isinf)= -### isinf(x, /) - -Tests each element `x_i` of the input array `x` to determine if equal to positive or negative infinity. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing test results. An element `out_i` is `True` if `x_i` is either positive or negative infinity and `False` otherwise. The returned array must have a data type of `bool`. - -(function-isnan)= -### isnan(x, /) - -Tests each element `x_i` of the input array `x` to determine whether the element is `NaN`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing test results. An element `out_i` is `True` if `x_i` is `NaN` and `False` otherwise. The returned array should have a data type of `bool`. - -(function-less)= -### less(x1, x2, /) - -Computes the truth value of `x1_i < x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-less_equal)= -### less_equal(x1, x2, /) - -Computes the truth value of `x1_i <= x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-log)= -### log(x, /) - -Calculates an implementation-dependent approximation to the natural (base `e`) logarithm, having domain `[0, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` of the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is less than `0`, the result is `NaN`. -- If `x_i` is either `+0` or `-0`, the result is `-infinity`. -- If `x_i` is `1`, the result is `+0`. -- If `x_i` is `+infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated natural logarithm for each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-log1p)= -### log1p(x, /) - -Calculates an implementation-dependent approximation to `log(1+x)`, where `log` refers to the natural (base `e`) logarithm, having domain `[-1, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` of the input array `x`. - -```{note} -The purpose of this function is to calculate `log(1+x)` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply `log(1+x)`. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. -``` - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is less than `-1`, the result is `NaN`. -- If `x_i` is `-1`, the result is `-infinity`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `+infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-log2)= -### log2(x, /) - -Calculates an implementation-dependent approximation to the base `2` logarithm, having domain `[0, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` of the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is less than `0`, the result is `NaN`. -- If `x_i` is either `+0` or `-0`, the result is `-infinity`. -- If `x_i` is `1`, the result is `+0`. -- If `x_i` is `+infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated base `2` logarithm for each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-log10)= -### log10(x, /) - -Calculates an implementation-dependent approximation to the base `10` logarithm, having domain `[0, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` of the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is less than `0`, the result is `NaN`. -- If `x_i` is either `+0` or `-0`, the result is `-infinity`. -- If `x_i` is `1`, the result is `+0`. -- If `x_i` is `+infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated base `10` logarithm for each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-logaddexp)= -### logaddexp(x1, x2) - -Calculates the logarithm of the sum of exponentiations `log(exp(x1) + exp(x2))` for -each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array -`x2`. - -#### Special Cases - -For floating-point operands, - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is `+infinity` and `x2_i` is not `NaN`, the result is `+infinity`. -- If `x1_i` is not `NaN` and `x2_i` is `+infinity`, the result is `+infinity`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a floating-point data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a floating-point - data type determined by {ref}`type-promotion`. - -(function-logical_and)= -### logical_and(x1, x2, /) - -Computes the logical AND for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -```{note} -While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. -``` - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a boolean data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-logical_not)= -### logical_not(x, /) - -Computes the logical NOT for each element `x_i` of the input array `x`. - -```{note} -While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-logical_or)= -### logical_or(x1, x2, /) - -Computes the logical OR for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -```{note} -While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. -``` - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a boolean data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-logical_xor)= -### logical_xor(x1, x2, /) - -Computes the logical XOR for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -```{note} -While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of `False`, while non-zeros must be considered the equivalent of `True`. -``` - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a boolean data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a boolean data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-multiply)= -### multiply(x1, x2, /) - -Calculates the product for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Special Cases - -For floating-point operands, - -- If either `x1_i` or `x2_i` is `NaN`, the result is `NaN`. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+0` or `-0`, the result is `NaN`. -- If `x1_i` is either `+0` or `-0` and `x2_i` is either `+infinity` or `-infinity`, the result is `NaN`. -- If `x1_i` and `x2_i` have the same mathematical sign, the result has a positive mathematical sign, unless the result is `NaN`. If the result is `NaN`, the "sign" of `NaN` is implementation-defined. -- If `x1_i` and `x2_i` have different mathematical signs, the result has a negative mathematical sign, unless the result is `NaN`. If the result is `NaN`, the "sign" of `NaN` is implementation-defined. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is either `+infinity` or `-infinity`, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- If `x1_i` is either `+infinity` or `-infinity` and `x2_i` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- If `x1_i` is a nonzero finite number and `x2_i` is either `+infinity` or `-infinity`, the result is a signed infinity with the mathematical sign determined by the rule already stated above. -- In the remaining cases, where neither `infinity` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. - -```{note} -Floating-point multiplication is not always associative due to finite precision. -``` - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise products. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-negative)= -### negative(x, /) - -Computes the numerical negative of each element `x_i` (i.e., `y_i = -x_i`) of the input array `x`. - -```{note} -For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `x`. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-not_equal)= -### not_equal(x1, x2, /) - -Computes the truth value of `x1_i != x2_i` for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. May have any data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type of `bool`. - -(function-positive)= -### positive(x, /) - -Computes the numerical positive of each element `x_i` (i.e., `y_i = +x_i`) of the input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `x`. The returned array must have the same data type as `x`. - -(function-pow)= -### pow(x1, x2, /) - -Calculates an implementation-dependent approximation of exponentiation by raising each element `x1_i` (the base) of the input array `x1` to the power of `x2_i` (the exponent), where `x2_i` is the corresponding element of the input array `x2`. - -```{note} -If both `x1` and `x2` have integer data types, the result of `pow` when `x2_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - -If `x1` has an integer data type and `x2` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. -``` - -#### Special Cases - -For floating-point operands, - -- If `x1_i` is not equal to `1` and `x2_i` is `NaN`, the result is `NaN`. -- If `x2_i` is `+0`, the result is `1`, even if `x1_i` is `NaN`. -- If `x2_i` is `-0`, the result is `1`, even if `x1_i` is `NaN`. -- If `x1_i` is `NaN` and `x2_i` is not equal to `0`, the result is `NaN`. -- If `abs(x1_i)` is greater than `1` and `x2_i` is `+infinity`, the result is `+infinity`. -- If `abs(x1_i)` is greater than `1` and `x2_i` is `-infinity`, the result is `+0`. -- If `abs(x1_i)` is `1` and `x2_i` is `+infinity`, the result is `1`. -- If `abs(x1_i)` is `1` and `x2_i` is `-infinity`, the result is `1`. -- If `x1_i` is `1` and `x2_i` is not `NaN`, the result is `1`. -- If `abs(x1_i)` is less than `1` and `x2_i` is `+infinity`, the result is `+0`. -- If `abs(x1_i)` is less than `1` and `x2_i` is `-infinity`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is greater than `0`, the result is `+infinity`. -- If `x1_i` is `+infinity` and `x2_i` is less than `0`, the result is `+0`. -- If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is an odd integer value, the result is `-infinity`. -- If `x1_i` is `-infinity`, `x2_i` is greater than `0`, and `x2_i` is not an odd integer value, the result is `+infinity`. -- If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is an odd integer value, the result is `-0`. -- If `x1_i` is `-infinity`, `x2_i` is less than `0`, and `x2_i` is not an odd integer value, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is greater than `0`, the result is `+0`. -- If `x1_i` is `+0` and `x2_i` is less than `0`, the result is `+infinity`. -- If `x1_i` is `-0`, `x2_i` is greater than `0`, and `x2_i` is an odd integer value, the result is `-0`. -- If `x1_i` is `-0`, `x2_i` is greater than `0`, and `x2_i` is not an odd integer value, the result is `+0`. -- If `x1_i` is `-0`, `x2_i` is less than `0`, and `x2_i` is an odd integer value, the result is `-infinity`. -- If `x1_i` is `-0`, `x2_i` is less than `0`, and `x2_i` is not an odd integer value, the result is `+infinity`. -- If `x1_i` is less than `0`, `x1_i` is a finite number, `x2_i` is a finite number, and `x2_i` is not an integer value, the result is `NaN`. - -#### Parameters - -- **x1**: _<array>_ - - - first input array whose elements correspond to the exponentiation base. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array whose elements correspond to the exponentiation exponent. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-remainder)= -### remainder(x1, x2, /) - -Returns the remainder of division for each element `x1_i` of the input array `x1` and the respective element `x2_i` of the input array `x2`. - -```{note} -For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. -``` - -#### Parameters - -- **x1**: _<array>_ - - - dividend input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - divisor input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element `x2_i`. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-round)= -### round(x, /) - -Rounds each element `x_i` of the input array `x` to the nearest integer-valued number. - -#### Special Cases - -- If `x_i` is already integer-valued, the result is `x_i`. - -For floating-point operands, - -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `-infinity`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `NaN`, the result is `NaN`. -- If two integers are equally close to `x_i`, the result is the even integer closest to `x_i`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the rounded result for each element in `x`. The returned array must have the same data type as `x`. - -(function-sign)= -### sign(x, /) - -Returns an indication of the sign of a number for each element `x_i` of the input array `x`. - -#### Special Cases - -- If `x_i` is less than `0`, the result is `-1`. -- If `x_i` is either `-0` or `+0`, the result is `0`. -- If `x_i` is greater than `0`, the result is `+1`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `x`. The returned array must have the same data type as `x`. - -(function-sin)= -### sin(x, /) - -Calculates an implementation-dependent approximation to the sine, having domain `(-infinity, +infinity)` and codomain `[-1, +1]`, for each element `x_i` of the input array `x`. Each element `x_i` is assumed to be expressed in radians. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is either `+infinity` or `-infinity`, the result is `NaN`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements are each expressed in radians. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the sine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-sinh)= -### sinh(x, /) - -Calculates an implementation-dependent approximation to the hyperbolic sine, having domain `[-infinity, +infinity]` and codomain `[-infinity, +infinity]`, for each element `x_i` of the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `-infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the hyperbolic sine of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-square)= -### square(x, /) - -Squares (`x_i * x_i`) each element `x_i` of the input array `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the evaluated result for each element in `x`. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-sqrt)= -### sqrt(x, /) - -Calculates the square root, having domain `[0, +infinity]` and codomain `[0, +infinity]`, for each element `x_i` of the input array `x`. After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is less than `0`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `+infinity`, the result is `+infinity`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the square root of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-subtract)= -### subtract(x1, x2, /) - -Calculates the difference for each element `x1_i` of the input array `x1` with the respective element `x2_i` of the input array `x2`. The result of `x1_i - x2_i` must be the same as `x1_i + (-x2_i)` and must be governed by the same floating-point rules as addition (see [`add()`](#addx1-x2-)). - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must be compatible with `x1` (see {ref}`broadcasting`). Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the element-wise differences. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-tan)= -### tan(x, /) - -Calculates an implementation-dependent approximation to the tangent, having domain `(-infinity, +infinity)` and codomain `(-infinity, +infinity)`, for each element `x_i` of the input array `x`. Each element `x_i` is assumed to be expressed in radians. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is either `+infinity` or `-infinity`, the result is `NaN`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements are expressed in radians. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the tangent of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-tanh)= -### tanh(x, /) - -Calculates an implementation-dependent approximation to the hyperbolic tangent, having domain `[-infinity, +infinity]` and codomain `[-1, +1]`, for each element `x_i` of the input array `x`. - -#### Special Cases - -For floating-point operands, - -- If `x_i` is `NaN`, the result is `NaN`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `+infinity`, the result is `+1`. -- If `x_i` is `-infinity`, the result is `-1`. - -#### Parameters - -- **x**: _<array>_ - - - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the hyperbolic tangent of each element in `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-trunc)= -### trunc(x, /) - -Rounds each element `x_i` of the input array `x` to the integer-valued number that is closest to but no greater than `x_i`. - -#### Special Cases - -- If `x_i` is already integer-valued, the result is `x_i`. - -For floating-point operands, - -- If `x_i` is `+infinity`, the result is `+infinity`. -- If `x_i` is `-infinity`, the result is `-infinity`. -- If `x_i` is `+0`, the result is `+0`. -- If `x_i` is `-0`, the result is `-0`. -- If `x_i` is `NaN`, the result is `NaN`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the rounded result for each element in `x`. The returned array must have the same data type as `x`. diff --git a/spec/API_specification/elementwise_functions.rst b/spec/API_specification/elementwise_functions.rst new file mode 100644 index 000000000..316ac8ce9 --- /dev/null +++ b/spec/API_specification/elementwise_functions.rst @@ -0,0 +1,86 @@ +.. _element-wise-functions: + +Element-wise Functions +====================== + + Array API specification for element-wise functions. + +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`. +- Functions may only be required for a subset of input data type. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in :ref:`accuracy`. + +Objects in API +-------------- + +.. currentmodule:: signatures.elementwise_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + abs + acos + acosh + add + asin + asinh + atan + atan2 + atanh + bitwise_and + bitwise_left_shift + bitwise_invert + bitwise_or + bitwise_right_shift + bitwise_xor + ceil + cos + cosh + divide + equal + exp + expm1 + floor + floor_divide + greater + greater_equal + isfinite + isinf + isnan + less + less_equal + log + log1p + log2 + log10 + logaddexp + logical_and + logical_not + logical_or + logical_xor + multiply + negative + not_equal + positive + pow + remainder + round + sign + sin + sinh + square + sqrt + subtract + tan + tanh + trunc diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 87a055366..e0eead8d2 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -133,7 +133,7 @@ def __abs__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-abs`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.abs`. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -179,7 +179,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-add`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.add`. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -200,7 +200,7 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_and`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_and`. """ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: @@ -334,7 +334,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.equal`. """ def __float__(self: array, /) -> float: @@ -409,7 +409,7 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-floor_divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.floor_divide`. """ def __ge__(self: array, other: Union[int, float, array], /) -> array: @@ -430,7 +430,7 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.greater_equal`. """ def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: @@ -468,7 +468,7 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-greater`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.greater`. """ def __index__(self: array, /) -> int: @@ -520,7 +520,7 @@ def __invert__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_invert`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_invert`. """ def __le__(self: array, other: Union[int, float, array], /) -> array: @@ -541,7 +541,7 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.less_equal`. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -562,7 +562,7 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_left_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: @@ -583,7 +583,7 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-less`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.less`. """ def __matmul__(self: array, other: array, /) -> array: @@ -646,7 +646,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-remainder`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.remainder`. """ def __mul__(self: array, other: Union[int, float, array], /) -> array: @@ -685,7 +685,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-multiply`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.multiply`. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -706,7 +706,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-not_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.not_equal`. """ def __neg__(self: array, /) -> array: @@ -728,7 +728,7 @@ def __neg__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-negative`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.negative`. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -749,7 +749,7 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_or`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -768,7 +768,7 @@ def __pos__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-positive`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.positive`. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: @@ -823,7 +823,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-pow`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.pow`. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -844,7 +844,7 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_right_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_right_shift`. """ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: @@ -888,7 +888,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-subtract`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.subtract`. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -941,7 +941,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.divide`. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: @@ -962,7 +962,7 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :ref:`function-bitwise_xor`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_xor`. """ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: diff --git a/spec/API_specification/signatures/elementwise_functions.py b/spec/API_specification/signatures/elementwise_functions.py new file mode 100644 index 000000000..0abb852d1 --- /dev/null +++ b/spec/API_specification/signatures/elementwise_functions.py @@ -0,0 +1,1361 @@ +from ._types import array + +def abs(x: array, /) -> array: + """ + Calculates the absolute value for each element ``x_i`` of the input array ``x`` (i.e., the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign). + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``-0``, the result is ``+0``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the absolute value of each element in ``x``. The returned array must have the same data type as ``x``. + """ + +def acos(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation of the principal value of the inverse cosine, having domain ``[-1, +1]`` and codomain ``[+0, +π]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def acosh(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine, having domain ``[+1, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def add(x1: array, x2: array, /) -> array: + """ + Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is ``-infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is a nonzero finite number, the result is ``x2_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. + - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. + + .. note:: + Floating-point addition is a commutative operation, but not always associative. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def asin(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation of the principal value of the inverse sine, having domain ``[-1, +1]`` and codomain ``[-π/2, +π/2]`` for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def asinh(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the inverse hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def atan(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation of the principal value of the inverse tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-π/2, +π/2]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def atan2(x1: array, x2: array, /) -> array: + """ + Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. + + The mathematical signs of ``x1_i`` and ``x2_i`` determine the quadrant of each element-wise result. The quadrant (i.e., branch) is chosen such that each element-wise result is the signed angle in radians between the ray ending at the origin and passing through the point ``(1,0)`` and the ray ending at the origin and passing through the point ``(x2_i, x1_i)``. + + .. note:: + Note the role reversal: the "y-coordinate" is the first function parameter; the "x-coordinate" is the second function parameter. The parameter order is intentional and traditional for the two-argument inverse tangent function where the y-coordinate argument is first and the x-coordinate argument is second. + + By IEEE 754 convention, the inverse tangent of the quotient ``x1/x2`` is defined for ``x2_i`` equal to positive or negative zero and for either or both of ``x1_i`` and ``x2_i`` equal to positive or negative ``infinity``. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is finite, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is finite, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/4``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. + + Parameters + ---------- + x1: array + input array corresponding to the y-coordinates. Should have a floating-point data type. + x2: array + input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + """ + +def atanh(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the inverse hyperbolic tangent, having domain ``[-1, +1]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``+1``, the result is ``+infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def bitwise_and(x1: array, x2: array, /) -> array: + """ + Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def bitwise_left_shift(x1: array, x2: array, /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. + + Parameters + ---------- + x1: array + first input array. Should have an integer data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def bitwise_invert(x: array, /) -> array: + """ + Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + """ + +def bitwise_or(x1: array, x2: array, /) -> array: + """ + Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def bitwise_right_shift(x1: array, x2: array, /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. + + Parameters + ---------- + x1: array + first input array. Should have an integer data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def bitwise_xor(x1: array, x2: array, /) -> array: + """ + Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def ceil(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + """ + +def cos(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the cosine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``NaN``. + - If ``x_i`` is ``-infinity``, the result is ``NaN``. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def cosh(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the hyperbolic cosine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def divide(x1: array, x2: array, /) -> array: + """ + Calculates the division for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + Parameters + ---------- + x1: array + dividend input array. Should have a numeric data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. May have any data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def exp(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the exponential function, having domain ``[-infinity, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+0``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def expm1(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to ``exp(x)-1``, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +infinity]``, for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def floor(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + """ + +def floor_divide(x1: array, x2: array, /) -> array: + """ + Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + **Special cases** + + .. note:: + Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``\s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + + To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. + + Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. + + This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + Parameters + ---------- + x1: array + dividend input array. Should have a numeric data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def greater(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def greater_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def isfinite(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if finite (i.e., not ``NaN`` and not equal to positive or negative infinity). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is finite and ``False`` otherwise. The returned array must have a data type of ``bool``. + """ + +def isinf(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is either positive or negative infinity and ``False`` otherwise. The returned array must have a data type of ``bool``. + """ + +def isnan(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is ``NaN`` and ``False`` otherwise. The returned array should have a data type of ``bool``. + """ + +def less(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def less_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def log(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def log1p(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, having domain ``[-1, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def log2(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the base ``2`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def log10(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the base ``10`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def logaddexp(x1: array, x2: array) -> array: + """ + Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + + Parameters + ---------- + x1: array + first input array. Should have a floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def logical_and(x1: array, x2: array, /) -> array: + """ + Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of `bool`. + """ + +def logical_not(x: array, /) -> array: + """ + Computes the logical NOT for each element ``x_i`` of the input array ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x: array + input array. Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def logical_or(x1: array, x2: array, /) -> array: + """ + Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def logical_xor(x1: array, x2: array, /) -> array: + """ + Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def multiply(x1: array, x2: array, /) -> array: + """ + Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign, the result has a positive mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` and ``x2_i`` have different mathematical signs, the result has a negative mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - In the remaining cases, where neither ``infinity`` nor ``NaN`` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def negative(x: array, /) -> array: + """ + Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def not_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. May have any data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + +def positive(x: array, /) -> array: + """ + Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + """ + +def pow(x1: array, x2: array, /) -> array: + """ + Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. + + .. note:: + If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + **Special cases** + + For floating-point operands, + + - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x2_i`` is ``-0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is not equal to ``0``, the result is ``NaN``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``+infinity``, the result is ``1``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``-infinity``, the result is ``1``. + - If ``x1_i`` is ``1`` and ``x2_i`` is not ``NaN``, the result is ``1``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is greater than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + + Parameters + ---------- + x1: array + first input array whose elements correspond to the exponentiation base. Should have a numeric data type. + x2: array + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def remainder(x1: array, x2: array, /) -> array: + """ + Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + x1: array + dividend input array. Should have a numeric data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def round(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + """ + +def sign(x: array, /) -> array: + """ + Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. + + **Special cases** + + - If ``x_i`` is less than ``0``, the result is ``-1``. + - If ``x_i`` is either ``-0`` or ``+0``, the result is ``0``. + - If ``x_i`` is greater than ``0``, the result is ``+1``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + """ + +def sin(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the sine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def sinh(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + + **Special cases** + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def square(x: array, /) -> array: + """ + Squares (``x_i * x_i``) each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def sqrt(x: array, /) -> array: + """ + Calculates the square root, having domain ``[0, +infinity]`` and codomain ``[0, +infinity]``, for each element ``x_i`` of the input array ``x``. After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def subtract(x1: array, x2: array, /) -> array: + """ + Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + """ + +def tan(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the tangent, having domain ``(-infinity, +infinity)`` and codomain ``(-infinity, +infinity)``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + Parameters + ---------- + x: array + input array whose elements are expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def tanh(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the hyperbolic tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. + + **Special cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+1``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + """ + +def trunc(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the integer-valued number that is closest to but no greater than ``x_i``. + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + """ + +__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] \ No newline at end of file From 488a04615e10bae57efbaa79863a6b8366c0e6db Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 31 Jan 2022 13:02:28 -0500 Subject: [PATCH 181/551] Remove extra md file --- spec/extensions/linear_algebra_functions.md | 624 -------------------- 1 file changed, 624 deletions(-) delete mode 100644 spec/extensions/linear_algebra_functions.md diff --git a/spec/extensions/linear_algebra_functions.md b/spec/extensions/linear_algebra_functions.md deleted file mode 100644 index 3d26436cc..000000000 --- a/spec/extensions/linear_algebra_functions.md +++ /dev/null @@ -1,624 +0,0 @@ -(linear-algebra-extension)= -# Linear Algebra Extension - -> Array API specification for linear algebra functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -## Design Principles - -A principal goal of this specification is to standardize commonly implemented interfaces among array libraries. While this specification endeavors to avoid straying too far from common practice, this specification does, with due restraint, seek to address design decisions arising more from historical accident than first principles. This is especially true for linear algebra APIs, which have arisen and evolved organically over time and have often been tied to particular underlying implementations (e.g., to BLAS and LAPACK). - -Accordingly, the standardization process affords the opportunity to reduce interface complexity among linear algebra APIs by inferring and subsequently codifying common design themes, thus allowing more consistent APIs. What follows is the set of design principles governing the APIs which follow: - -1. **Batching**: if an operation is explicitly defined in terms of matrices (i.e., two-dimensional arrays), then the associated interface should support "batching" (i.e., the ability to perform the operation over a "stack" of matrices). Example operations include: - - - `inv`: computing the multiplicative inverse of a square matrix. - - `cholesky`: performing Cholesky decomposition. - - `matmul`: performing matrix multiplication. - -2. **Data types**: if an operation requires decimal operations and {ref}`type-promotion` semantics are undefined (e.g., as is the case for mixed-kind promotions), then the associated interface should be specified as being restricted to floating-point data types. While the specification uses the term "SHOULD" rather than "MUST", a conforming implementation of the array API standard should only ignore the restriction provided overly compelling reasons for doing so. Example operations which should be limited to floating-point data types include: - - - `inv`: computing the multiplicative inverse. - - `slogdet`: computing the natural logarithm of the absolute value of the determinant. - - `norm`: computing the matrix or vector norm. - - Certain operations are solely comprised of multiplications and additions. Accordingly, associated interfaces need not be restricted to floating-point data types. However, careful consideration should be given to overflow, and use of floating-point data types may be more prudent in practice. Example operations include: - - - `matmul`: performing matrix multiplication. - - `trace`: computing the sum along the diagonal. - - `cross`: computing the vector cross product. - - Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: - - - `matrix_transpose`: computing the transpose. - - `diagonal`: returning the diagonal. - -3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. - - In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - - `eig`: computing both eigenvalues and eignvectors. - - `eigvals`: computing only eigenvalues. - -4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. - - Historically, at a time when all array computing happened on CPUs, BLAS and LAPACK underpinned most numerical computing libraries and environments. Naturally, language and library abstractions catered to the parameterization of those libraries, often exposing low-level implementation details verbatim in their higher-level interfaces, even if such choices would be considered poor or ill-advised by today's standards (e.g., NumPy's use of `UPLO` in `eigh`). However, the present day is considerably different. While still important, BLAS and LAPACK no longer hold a monopoly over linear algebra operations, especially given the proliferation of devices and hardware on which such operations must be performed. Accordingly, interfaces must be conservative in the parameterization they support in order to best ensure universality. Such conservatism applies even to performance optimization parameters afforded by certain hardware. - -5. **Orthogonality**: an interface should have clearly defined and delineated functionality which, ideally, has no overlap with the functionality of other interfaces in the specification. Providing multiple interfaces which can all perform the same operation creates unnecessary confusion regarding interface applicability (i.e., which interface is best at which time) and decreases readability of both library and user code. Where overlap is possible, the specification must be parsimonious in the number of interfaces, ensuring that each interface provides a unique and compelling abstraction. Examples of related interfaces which provide distinct levels of abstraction (and generality) include: - - - `vecdot`: computing the dot product of two vectors. - - `matmul`: performing matrix multiplication (including between two vectors and thus the dot product). - - `tensordot`: computing tensor contractions (generalized sum-products). - - `einsum`: expressing operations in terms of Einstein summation convention, including dot products and tensor contractions. - - The above can be contrasted with, e.g., NumPy, which provides the following interfaces for computing the dot product or related operations: - - - `dot`: dot product, matrix multiplication, and tensor contraction. - - `inner`: dot product. - - `vdot`: dot product with flattening and complex conjugation. - - `multi_dot`: chained dot product. - - `tensordot`: tensor contraction. - - `matmul`: matrix multiplication (dot product for two vectors). - - `einsum`: Einstein summation convention. - - where `dot` is overloaded based on input array dimensionality and `vdot` and `inner` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. - -## Objects in API - - - -(function-linalg-cholesky)= -### linalg.cholesky(x, /, *, upper=False) - -Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symmetric positive-definite matrix (or a stack of matrices) `x`, where `L` is a lower-triangular matrix or a stack of matrices (`U` is an upper-triangular matrix or a stack of matrices). - - - -```{note} -Whether an array library explicitly checks whether an input array is a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square symmetric positive-definite matrices. Should have a floating-point data type. - -- **upper**: _bool_ - - - If `True`, the result must be the upper-triangular Cholesky factor `U`. If `False`, the result must be the lower-triangular Cholesky factor `L`. Default: `False`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the Cholesky factors for each square matrix. If `upper` is `False`, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have the same shape as `x`. - -(function-linalg-cross)= -### linalg.cross(x1, x2, /, *, axis=-1) - -Returns the cross product of 3-element vectors. If `x1` and `x2` are multi-dimensional arrays (i.e., both have a rank greater than `1`), then the cross-product of each pair of corresponding 3-element vectors is independently computed. - -#### Parameters - -- **x1**: _<array>_ - - - first input array. Should have a numeric data type. - -- **x2**: _<array>_ - - - second input array. Must have the same shape as `x1`. Should have a numeric data type. - -- **axis**: _int_ - - - the axis (dimension) of `x1` and `x2` containing the vectors for which to compute the cross product. If set to `-1`, the function computes the cross product for vectors defined by the last axis (dimension). Default: `-1`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the cross products. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-linalg-det)= -### linalg.det(x, /) - -Returns the determinant of a square matrix (or a stack of square matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - if `x` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as `x`. - -(function-linalg-diagonal)= -### linalg.diagonal(x, /, *, offset=0) - -Returns the specified diagonals of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. - -- **offset**: _int_ - - - offset specifying the off-diagonal relative to the main diagonal. - - - `offset = 0`: the main diagonal. - - `offset > 0`: off-diagonal above the main diagonal. - - `offset < 0`: off-diagonal below the main diagonal. - - Default: `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as `x`. - -(function-linalg-eigh)= -### linalg.eigh(x, /) - -```{note} -The function `eig` will be added in a future version of the specification, as it requires complex number support. -``` - -Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) `x`, where `Q` is an orthogonal matrix (or a stack of matrices) and `L` is a vector (or a stack of vectors). - - - -```{note} -Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must have a floating-point data type. - -#### Returns - -- **out**: _Tuple\[ <array> ]_ - - - a namedtuple (`eigenvalues`, `eigenvectors`) whose - - - first element must have the field name `eigenvalues` (corresponding to `L` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape `(..., M)`. - - second element have have the field name `eigenvectors` (corresponding to `Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape `(..., M, M)`. - - Each returned array must have the same floating-point data type as `x`. - -```{note} -Eigenvalue sort order is left unspecified and is thus implementation-dependent. -``` - -(function-linalg-eigvalsh)= -### linalg.eigvalsh(x, /) - -```{note} -The function `eigvals` will be added in a future version of the specification, as it requires complex number support. -``` - -Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) `x`. - - - -```{note} -Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the computed eigenvalues. The returned array must have shape `(..., M)` and have the same data type as `x`. - -```{note} -Eigenvalue sort order is left unspecified and is thus implementation-dependent. -``` - -(function-linalg-inv)= -### linalg.inv(x, /) - -Returns the multiplicative inverse of a square matrix (or a stack of square matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have the same shape as `x`. - -(function-linalg-matmul)= -### linalg.matmul(x1, x2, /) - -Alias for {func}`signatures.linear_algebra_functions.matmul`. - -(function-linalg-matrix-norm)= -### linalg.matrix_norm(x, /, *, keepdims=False, ord='fro') - -Computes the matrix norm of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - -- **keepdims**: _bool_ - - - If `True`, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the last two axes (dimensions) must not be included in the result. Default: `False`. - -- **ord**: _Optional\[ Union\[ int, float, Literal\[ inf, -inf, 'fro', 'nuc' ] ] ]_ - - - order of the norm. The following mathematical norms must be supported: - | ord | description | - | ---------------- | ------------------------------- | - | 'fro' | Frobenius norm | - | 'nuc' | nuclear norm | - | 1 | max(sum(abs(x), axis=0)) | - | 2 | largest singular value | - | inf | max(sum(abs(x), axis=1)) | - - The following non-mathematical "norms" must be supported: - | ord | description | - | ---------------- | ------------------------------- | - | -1 | min(sum(abs(x), axis=0)) | - | -2 | smallest singular value | - | -inf | min(sum(abs(x), axis=1)) | - - If `ord=1`, the norm corresponds to the induced matrix norm where `p=1` (i.e., the maximum absolute value column sum). - - If `ord=2`, the norm corresponds to the induced matrix norm where `p=inf` (i.e., the maximum absolute value row sum). - - If `ord=inf`, the norm corresponds to the induced matrix norm where `p=2` (i.e., the largest singular value). - - Default: `'fro'`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the norms for each `MxN` matrix. If `keepdims` is `False`, the returned array must have a rank which is two less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-matrix_power)= -### linalg.matrix_power(x, n, /) - -Raises a square matrix (or a stack of square matrices) `x` to an integer power `n`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -- **n**: _int_ - - - integer exponent. - -#### Returns - -- **out**: _<array>_ - - - if `n` is equal to zero, an array containing the identity matrix for each square matrix. If `n` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of `n`, provided that each square matrix is invertible. If `n` is greater than zero, an array containing the result of raising each square matrix to the power `n`. The returned array must have the same shape as `x` and a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-matrix_rank)= -### linalg.matrix_rank(x, /, *, rtol=None) - -Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - -- **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - - relative tolerance for small singular values. Singular values approximately less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the ranks. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have shape `(...)` (i.e., must have a shape equal to `shape(x)[:-2]`). - -(function-linalg-matrix-transpose)= -### linalg.matrix_transpose(x, /) - -Alias for {func}`signatures.linear_algebra_functions.matrix_transpose`. - -(function-linalg-outer)= -### linalg.outer(x1, x2, /) - -Returns the outer product of two vectors `x1` and `x2`. - -#### Parameters - -- **x1**: _<array>_ - - - first one-dimensional input array of size `N`. Should have a numeric data type. - -- **x2**: _<array>_ - - - second one-dimensional input array of size `M`. Should have a numeric data type. - -#### Returns - -- **out**: _<array>_ - - - a two-dimensional array containing the outer product and whose shape is `(N, M)`. The returned array must have a data type determined by {ref}`type-promotion`. - -(function-linalg-pinv)= -### linalg.pinv(x, /, *, rtol=None) - -Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a floating-point data type. - -- **rtol**: _Optional\[ Union\[ float, <array> ] ]_ - - - relative tolerance for small singular values. Singular values approximately less than or equal to `rtol * largest_singular_value` are set to zero. If a `float`, the value is equivalent to a zero-dimensional array having a floating-point data type determined by {ref}`type-promotion` (as applied to `x`) and must be broadcast against each matrix. If an `array`, must have a floating-point data type and must be compatible with `shape(x)[:-2]` (see {ref}`broadcasting`). If `None`, the default value is `max(M, N) * eps`, where `eps` must be the machine epsilon associated with the floating-point data type determined by {ref}`type-promotion` (as applied to `x`). Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the pseudo-inverses. The returned array must have a floating-point data type determined by {ref}`type-promotion` and must have shape `(..., N, M)` (i.e., must have the same shape as `x`, except the innermost two dimensions must be transposed). - -(function-linalg-qr)= -### linalg.qr(x, /, *, mode='reduced') - -Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where `Q` is an orthonormal matrix (or a stack of matrices) and `R` is an upper-triangular matrix (or a stack of matrices). - -```{note} -Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices of rank `N`. Should have a floating-point data type. - -- **mode**: _Literal\[ 'reduced', 'complete' ]_ - - - decomposition mode. Should be one of the following modes: - - - `'reduced'`: compute only the leading `K` columns of `q`, such that `q` and `r` have dimensions `(..., M, K)` and `(..., K, N)`, respectively, and where `K = min(M, N)`. - - `'complete'`: compute `q` and `r` with dimensions `(..., M, M)` and `(..., M, N)`, respectively. - - Default: `'reduced'`. - -#### Returns - -- **out**: _Tuple\[ <array>, <array> ]_ - - - a namedtuple `(Q, R)` whose - - - first element must have the field name `Q` and must be an array whose shape depends on the value of `mode` and contain matrices with orthonormal columns. If `mode` is `'complete'`, the array must have shape `(..., M, M)`. If `mode` is `'reduced'`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input array `x`. - - second element must have the field name `R` and must be an array whose shape depends on the value of `mode` and contain upper-triangular matrices. If `mode` is `'complete'`, the array must have shape `(..., M, N)`. If `mode` is `'reduced'`, the array must have shape `(..., K, N)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same size as those of the input `x`. - - Each returned array must have a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-slogdet)= -### linalg.slogdet(x, /) - -Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) `x`. - -```{note} -The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling `det` may overflow or underflow. -``` - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Should have a floating-point data type. - -#### Returns - -- **out**: _Tuple\[ <array>, <array> ]_ - - - a namedtuple (`sign`, `logabsdet`) whose - - - first element must have the field name `sign` and must be an array containing a number representing the sign of the determinant for each square matrix. - - second element must have the field name `logabsdet` and must be an array containing the determinant for each square matrix. - - For a real matrix, the sign of the determinant must be either `1`, `0`, or `-1`. - - Each returned array must have shape `shape(x)[:-2]` and a floating-point data type determined by {ref}`type-promotion`. - - ```{note} - If a determinant is zero, then the corresponding `sign` should be `0` and `logabsdet` should be `-infinity`; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to `sign * exp(logsabsdet)` (although, again, the result may be subject to numerical precision errors). - ``` - -(function-linalg-solve)= -### linalg.solve(x1, x2, /) - -Returns the solution to the system of linear equations represented by the well-determined (i.e., full rank) linear matrix equation `AX = B`. - -```{note} -Whether an array library explicitly checks whether an input array is full rank is implementation-defined. -``` - -#### Parameters - -- **x1**: _<array>_ - - - coefficient array `A` having shape `(..., M, M)` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. - -- **x2**: _<array>_ - - - ordinate (or "dependent variable") array `B`. If `x2` has shape `(M,)`, `x2` is equivalent to an array having shape `(..., M, 1)`. If `x2` has shape `(..., M, K)`, each column `k` defines a set of ordinate values for which to compute a solution, and `shape(x2)[:-1]` must be compatible with `shape(x1)[:-1]` (see {ref}`broadcasting`). Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array containing the solution to the system `AX = B` for each square matrix. The returned array must have the same shape as `x2` (i.e., the array corresponding to `B`) and must have a floating-point data type determined by {ref}`type-promotion`. - -(function-linalg-svd)= -### linalg.svd(x, /, *, full_matrices=True) - -Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) `x`, where `U` is a matrix (or a stack of matrices) with orthonormal columns, `S` is a vector of non-negative numbers (or stack of vectors), and `Vh` is a matrix (or a stack of matrices) with orthonormal rows. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. - -- **full_matrices**: _bool_ - - - If `True`, compute full-sized `U` and `Vh`, such that `U` has shape `(..., M, M)` and `Vh` has shape `(..., N, N)`. If `False`, compute on the leading `K` singular vectors, such that `U` has shape `(..., M, K)` and `Vh` has shape `(..., K, N)` and where `K = min(M, N)`. Default: `True`. - -#### Returns - - - -- **out**: _Union\[ <array>, Tuple\[ <array>, ... ] ]_ - - - a namedtuple `(U, S, Vh)` whose - - - first element must have the field name `U` and must be an array whose shape depends on the value of `full_matrices` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If `full_matrices` is `True`, the array must have shape `(..., M, M)`. If `full_matrices` is `False`, the array must have shape `(..., M, K)`, where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - second element must have the field name `S` and must be an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`, where `K = min(M, N)`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - third element must have the field name `Vh` and must be an array whose shape depends on the value of `full_matrices` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If `full_matrices` is `True`, the array must have shape `(..., N, N)`. If `full_matrices` is `False`, the array must have shape `(..., K, N)` where `K = min(M, N)`. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. - - Each returned array must have the same floating-point data type as `x`. - -(function-linalg-svdvals)= -### linalg.svdvals(x, /) - -Returns the singular values of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. - -#### Returns - -- **out**: _<array>_ - - - an array with shape `(..., K)` that contains the vector(s) of singular values of length `K`, where `K = min(M, N)`. For each vector, the singular values must be sorted in descending order by magnitude, such that `s[..., 0]` is the largest value, `s[..., 1]` is the second largest value, et cetera. The first `x.ndim-2` dimensions must have the same shape as those of the input `x`. The returned array must have the same floating-point data type as `x`. - -(function-linalg-tensordot)= -### linalg.tensordot(x1, x2, /, *, axes=2) - -Alias for {func}`signatures.linear_algebra_functions.tensordot`. - -(function-linalg-trace)= -### linalg.trace(x, /, *, offset=0) - -Returns the sum along the specified diagonals of a matrix (or a stack of matrices) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array having shape `(..., M, N)` and whose innermost two dimensions form `MxN` matrices. Should have a numeric data type. - -- **offset**: _int_ - - - offset specifying the off-diagonal relative to the main diagonal. - - - `offset = 0`: the main diagonal. - - `offset > 0`: off-diagonal above the main diagonal. - - `offset < 0`: off-diagonal below the main diagonal. - - Default: `0`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if `x` has rank `k` and shape `(I, J, K, ..., L, M, N)`, then an output array has rank `k-2` and shape `(I, J, K, ..., L)` where - - ```text - out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) - ``` - - The returned array must have the same data type as `x`. - -(function-linalg-vecdot)= -### linalg.vecdot(x1, x2, /, *, axis=-1) - -Alias for {func}`signatures.linear_algebra_functions.vecdot`. - -(function-linalg-vector-norm)= -### linalg.vector_norm(x, /, *, axis=None, keepdims=False, ord=2) - -Computes the vector norm of a vector (or batch of vectors) `x`. - -#### Parameters - -- **x**: _<array>_ - - - input array. Should have a floating-point data type. - -- **axis**: _Optional\[ Union\[ int, Tuple\[ int, ... ] ] ]_ - - - If an integer, `axis` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, `axis` specifies the axes (dimensions) along which to compute batched vector norms. If `None`, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: `None`. - -- **keepdims**: _bool_ - - - If `True`, the axes (dimensions) specified by `axis` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see {ref}`broadcasting`). Otherwise, if `False`, the axes (dimensions) specified by `axis` must not be included in the result. Default: `False`. - -- **ord**: _Union\[ int, float, Literal\[ inf, -inf ] ]_ - - - order of the norm. The following mathematical norms must be supported: - | ord | description | - | ---------------- | -------------------------- | - | 1 | L1-norm (Manhattan) | - | 2 | L2-norm (Euclidean) | - | inf | infinity norm | - | (int,float >= 1) | p-norm | - - The following non-mathematical "norms" must be supported: - | ord | description | - | ---------------- | ------------------------------ | - | 0 | sum(a != 0) | - | -1 | 1./sum(1./abs(a)) | - | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | - | -inf | min(abs(a)) | - | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | - - Default: `2`. - -#### Returns - -- **out**: _<array>_ - - - an array containing the vector norms. If `axis` is `None`, the returned array must be a zero-dimensional array containing a vector norm. If `axis` is a scalar value (`int` or `float`), the returned array must have a rank which is one less than the rank of `x`. If `axis` is a `n`-tuple, the returned array must have a rank which is `n` less than the rank of `x`. The returned array must have a floating-point data type determined by {ref}`type-promotion`. From 9c475eb94743c98cf73f1f964b97d07abcae9df2 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 31 Jan 2022 13:22:06 -0500 Subject: [PATCH 182/551] Add ~ to show only the function name --- .../signatures/array_object.py | 50 +++++++++---------- .../extension_linear_algebra_functions.py | 8 +-- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index e0eead8d2..9098f0e2e 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -133,7 +133,7 @@ def __abs__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.abs`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.abs`. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -179,7 +179,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.add`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.add`. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -200,7 +200,7 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_and`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_and`. """ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: @@ -237,7 +237,7 @@ def __bool__(self: array, /) -> bool: def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: """ - Exports the array for consumption by :func:`signatures.creation_functions.from_dlpack` as a DLPack capsule. + Exports the array for consumption by :func:`~signatures.creation_functions.from_dlpack` as a DLPack capsule. Parameters ---------- @@ -292,7 +292,7 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: """ - Returns device type and device ID in DLPack format. Meant for use within :func:`signatures.creation_functions.from_dlpack`. + Returns device type and device ID in DLPack format. Meant for use within :func:`~signatures.creation_functions.from_dlpack`. Parameters ---------- @@ -334,7 +334,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.equal`. """ def __float__(self: array, /) -> float: @@ -409,7 +409,7 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.floor_divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.floor_divide`. """ def __ge__(self: array, other: Union[int, float, array], /) -> array: @@ -430,7 +430,7 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.greater_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater_equal`. """ def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: @@ -468,7 +468,7 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.greater`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater`. """ def __index__(self: array, /) -> int: @@ -520,7 +520,7 @@ def __invert__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_invert`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_invert`. """ def __le__(self: array, other: Union[int, float, array], /) -> array: @@ -541,7 +541,7 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.less_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less_equal`. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -562,7 +562,7 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_left_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: @@ -583,7 +583,7 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.less`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less`. """ def __matmul__(self: array, other: array, /) -> array: @@ -614,7 +614,7 @@ def __matmul__(self: array, other: array, /) -> array: .. note:: - Results must equal the results returned by the equivalent function :func:`signatures.linear_algebra_functions.matmul`. + Results must equal the results returned by the equivalent function :func:`~signatures.linear_algebra_functions.matmul`. **Raises** @@ -646,7 +646,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.remainder`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.remainder`. """ def __mul__(self: array, other: Union[int, float, array], /) -> array: @@ -685,7 +685,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.multiply`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.multiply`. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -706,7 +706,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.not_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.not_equal`. """ def __neg__(self: array, /) -> array: @@ -728,7 +728,7 @@ def __neg__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.negative`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.negative`. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -749,7 +749,7 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_or`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -768,7 +768,7 @@ def __pos__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.positive`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.positive`. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: @@ -823,7 +823,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.pow`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.pow`. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -844,7 +844,7 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_right_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_right_shift`. """ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: @@ -888,7 +888,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.subtract`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.subtract`. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -941,7 +941,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.divide`. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: @@ -962,7 +962,7 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`signatures.elementwise_functions.bitwise_xor`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_xor`. """ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: diff --git a/spec/API_specification/signatures/extension_linear_algebra_functions.py b/spec/API_specification/signatures/extension_linear_algebra_functions.py index 3235edf13..8a0db9c70 100644 --- a/spec/API_specification/signatures/extension_linear_algebra_functions.py +++ b/spec/API_specification/signatures/extension_linear_algebra_functions.py @@ -158,7 +158,7 @@ def inv(x: array, /) -> array: def matmul(x1: array, x2: array, /) -> array: """ - Alias for :func:`signatures.linear_algebra_functions.matmul`. + Alias for :func:`~signatures.linear_algebra_functions.matmul`. """ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: @@ -250,7 +250,7 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a def matrix_transpose(x: array, /) -> array: """ - Alias for :func:`signatures.linear_algebra_functions.matrix_transpose`. + Alias for :func:`~signatures.linear_algebra_functions.matrix_transpose`. """ def outer(x1: array, x2: array, /) -> array: @@ -407,7 +407,7 @@ def svdvals(x: array, /) -> array: def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: """ - Alias for :func:`signatures.linear_algebra_functions.tensordot`. + Alias for :func:`~signatures.linear_algebra_functions.tensordot`. """ def trace(x: array, /, *, offset: int = 0) -> array: @@ -441,7 +441,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ - Alias for :func:`signatures.linear_algebra_functions.vecdot`. + Alias for :func:`~signatures.linear_algebra_functions.vecdot`. """ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: From 1b50178ca382a0517a3c517c4cc6a958b5f4be54 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 1 Feb 2022 11:43:48 -0500 Subject: [PATCH 183/551] Rename to linalg --- .../{extension_linear_algebra_functions.py => linalg.py} | 0 spec/extensions/linear_algebra_functions.rst | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename spec/API_specification/signatures/{extension_linear_algebra_functions.py => linalg.py} (100%) diff --git a/spec/API_specification/signatures/extension_linear_algebra_functions.py b/spec/API_specification/signatures/linalg.py similarity index 100% rename from spec/API_specification/signatures/extension_linear_algebra_functions.py rename to spec/API_specification/signatures/linalg.py diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/extensions/linear_algebra_functions.rst index 8ad1ad487..b82a913de 100644 --- a/spec/extensions/linear_algebra_functions.rst +++ b/spec/extensions/linear_algebra_functions.rst @@ -74,7 +74,7 @@ Accordingly, the standardization process affords the opportunity to reduce inter where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. -.. currentmodule:: signatures.extension_linear_algebra_functions +.. currentmodule:: signatures.linalg Objects in API -------------- From 8d4ae62154b32611e213e1fabae7f79a558dd25c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 7 Feb 2022 14:42:52 -0500 Subject: [PATCH 184/551] Transform data type function specification to rST (#349) * Transform data_type_functions.md to rst * Fix title case * Update notes and fix non existent labels * Add bullet points * Remove raises section * Move sentence Co-authored-by: Athan --- spec/API_specification/data_type_functions.md | 181 ------------------ .../API_specification/data_type_functions.rst | 27 +++ .../signatures/creation_functions.py | 2 +- .../signatures/data_type_functions.py | 159 +++++++++++++++ 4 files changed, 187 insertions(+), 182 deletions(-) delete mode 100644 spec/API_specification/data_type_functions.md create mode 100644 spec/API_specification/data_type_functions.rst create mode 100644 spec/API_specification/signatures/data_type_functions.py diff --git a/spec/API_specification/data_type_functions.md b/spec/API_specification/data_type_functions.md deleted file mode 100644 index 69a595b93..000000000 --- a/spec/API_specification/data_type_functions.md +++ /dev/null @@ -1,181 +0,0 @@ -# Data type functions - -> Array API specification for data type functions. - -A conforming implementation of the array API standard must provide and support the following data type functions. - - - -## Objects in API - -(function-astype)= -### astype(x, dtype, /, *, copy=True) - -Copies an array to a specified data type irrespective of {ref}`type-promotion` rules. - -```{note} -Casting floating-point `NaN` and `infinity` values to integral data types is not specified and is implementation-dependent. -``` - -```{note} -When casting a boolean input array to a numeric data type, a value of `True` must cast to a numeric value equal to `1`, and a value of `False` must cast to a numeric value equal to `0`. - -When casting a numeric input array to `bool`, a value of `0` must cast to `False`, and a non-zero value must cast to `True`. -``` - -#### Parameters - -- **x**: _<array>_ - - - array to cast. - -- **dtype**: _<dtype>_ - - - desired data type. - -- **copy**: _<bool>_ - - - specifies whether to copy an array when the specified `dtype` matches the data type of the input array `x`. If `True`, a newly allocated array must always be returned. If `False` and the specified `dtype` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated must be returned. Default: `True`. - -#### Returns - -- **out**: _<array>_ - - - an array having the specified data type. The returned array must have the same shape as `x`. - -(function-broadcast_arrays)= -### broadcast_arrays(*arrays) - -Broadcasts one or more arrays against one another. - -#### Parameters - -- **arrays**: _<array>_ - - - an arbitrary number of to-be broadcasted arrays. - -#### Returns - -- **out**: _List\[ <array> ]_ - - - a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. - -(function-broadcast_to)= -### broadcast_to(x, /, shape) - -Broadcasts an array to a specified shape. - -#### Parameters - -- **x**: _<array>_ - - - array to broadcast. - -- **shape**: _Tuple\[int, ...]_ - - - array shape. Must be compatible with `x` (see {ref}`broadcasting`). - -#### Returns - -- **out**: _<array>_ - - - an array having a specified shape. Must have the same data type as `x`. - -#### Raises - -- if the array is incompatible with the specified shape (see {ref}`broadcasting`). - -(function-can_cast)= -### can_cast(from_, to, /) - -Determines if one data type can be cast to another data type according {ref}`type-promotion` rules. - -#### Parameters - -- **from_**: _Union\[ <dtype>, <array>]_ - - - input data type or array from which to cast. - -- **to**: _<dtype>_ - - - desired data type. - -#### Returns - -- **out**: _bool_ - - - `True` if the cast can occur according to {ref}`type-promotion` rules; otherwise, `False`. - -(function-finfo)= -### finfo(type, /) - -Machine limits for floating-point data types. - -#### Parameters - -- **type**: _Union\[ <dtype>, <array> ]_ - - - the kind of floating-point data-type about which to get information. - -#### Returns - -- **out**: _<finfo object>_ - - - an object having the following attributes: - - - **bits**: _int_ - - number of bits occupied by the floating-point data type. - - **eps**: _float_ - - difference between 1.0 and the next smallest representable floating-point number larger than 1.0 according to the IEEE-754 standard. - - **max**: _float_ - - largest representable number. - - **min**: _float_ - - smallest representable number. - - **smallest_normal**: _float_ - - smallest positive floating-point number with full precision. - -(function-iinfo)= -### iinfo(type, /) - -Machine limits for integer data types. - -#### Parameters - -- **type**: _Union\[ <dtype>, <array> ]_ - - - the kind of integer data-type about which to get information. - -#### Returns - -- **out**: _<iinfo object>_ - - - a class with that encapsules the following attributes: - - - **bits**: _int_ - - number of bits occupied by the type - - **max**: _int_ - - largest representable number. - - **min**: _int_ - - smallest representable number. - -(function-result_type)= -### result_type(*arrays_and_dtypes) - -Returns the dtype that results from applying the type promotion rules -(see {ref}`type-promotion`) to the arguments. - -```{note} -If provided mixed dtypes (e.g., integer and floating-point), the returned dtype will be implementation-specific. -``` - -#### Parameters - -- **arrays_and_dtypes**: _Union\[ <array>, <dtype> \]_ - - - an arbitrary number of input arrays and/or dtypes. - -#### Returns - -- **out**: _<dtype>_ - - - the dtype resulting from an operation involving the input arrays and dtypes. diff --git a/spec/API_specification/data_type_functions.rst b/spec/API_specification/data_type_functions.rst new file mode 100644 index 000000000..4b35a297a --- /dev/null +++ b/spec/API_specification/data_type_functions.rst @@ -0,0 +1,27 @@ +Data Type Functions +=================== + + Array API specification for data type functions. + +A conforming implementation of the array API standard must provide and support the following data type functions. + + +Objects in API +-------------- + +.. currentmodule:: signatures.data_type_functions + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + astype + broadcast_arrays + broadcast_to + can_cast + finfo + iinfo + result_type diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index aa25a24a2..0cb199850 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -54,7 +54,7 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr .. admonition:: Note :class: note - If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :ref:`function-astype`. + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`signatures.data_type_functions.astype`. device: Optional[device] device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. diff --git a/spec/API_specification/signatures/data_type_functions.py b/spec/API_specification/signatures/data_type_functions.py new file mode 100644 index 000000000..2356a8b2e --- /dev/null +++ b/spec/API_specification/signatures/data_type_functions.py @@ -0,0 +1,159 @@ +from ._types import List, Tuple, Union, array, dtype, finfo_object, iinfo_object + +def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: + """ + Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. + + .. note:: + Casting floating-point ``NaN`` and ``infinity`` values to integral data types is not specified and is implementation-dependent. + + .. note:: + When casting a boolean input array to a numeric data type, a value of ``True`` must cast to a numeric value equal to ``1``, and a value of ``False`` must cast to a numeric value equal to ``0``. + + When casting a numeric input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. + + Parameters + ---------- + x: array + array to cast. + dtype: dtype + desired data type. + copy: bool + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated must be returned. Default: ``True``. + + Returns + ------- + out: array + an array having the specified data type. The returned array must have the same shape as ``x``. + """ + +def broadcast_arrays(*arrays: array) -> List[array]: + """ + Broadcasts one or more arrays against one another. + + Parameters + ---------- + arrays: array + an arbitrary number of to-be broadcasted arrays. + + Returns + ------- + out: List[array] + a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. + """ + +def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: + """ + Broadcasts an array to a specified shape. + + Parameters + ---------- + x: array + array to broadcast. + shape: Tuple[int, ...] + array shape. Must be compatible with ``x`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + + Returns + ------- + out: array + an array having a specified shape. Must have the same data type as ``x``. + """ + +def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: + """ + Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. + + Parameters + ---------- + from_: Union[dtype, array] + input data type or array from which to cast. + to: dtype + desired data type. + + Returns + ------- + out: bool + ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. + """ + +def finfo(type: Union[dtype, array], /) -> finfo_object: + """ + Machine limits for floating-point data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of floating-point data-type about which to get information. + + Returns + ------- + out: finfo object + an object having the followng attributes: + + - **bits**: *int* + + number of bits occupied by the floating-point data type. + + - **eps**: *float* + + difference between 1.0 and the next smallest representable floating-point number larger than 1.0 according to the IEEE-754 standard. + + - **max**: *float* + + largest representable number. + + - **min**: *float* + + smallest representable number. + + - **smallest_normal**: *float* + + smallest positive floating-point number with full precision. + """ + +def iinfo(type: Union[dtype, array], /) -> iinfo_object: + """ + Machine limits for integer data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of integer data-type about which to get information. + + Returns + ------- + out: iinfo object + a class with that encapsules the following attributes: + + - **bits**: *int* + + number of bits occupied by the type. + + - **max**: *int* + + largest representable number. + + - **min**: *int* + + smallest representable number. + """ + +def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: + """ + Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. + + .. note:: + If provided mixed dtypes (e.g., integer and floating-point), the returned dtype will be implementation-specific. + + Parameters + ---------- + arrays_and_dtypes: Union[array, dtype] + an arbitrary number of input arrays and/or dtypes. + + Returns + ------- + out: dtype + the dtype resulting from an operation involving the input arrays and dtypes. + """ + +__all__ = ['astype', 'broadcast_arrays', 'broadcast_to', 'can_cast', 'finfo', 'iinfo', 'result_type'] From ee3f3b07abee4becfdbfe0f0ed4bf765c265f54e Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 7 Feb 2022 20:49:18 -0700 Subject: [PATCH 185/551] Disable the html_prettify setting (#389) This fixes the issue where every code block would have an extra space inserted after it. Fixes #139. --- spec/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/conf.py b/spec/conf.py index 48fe552db..da30e54b0 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -114,7 +114,7 @@ #'repo_name': 'Project', "html_minify": False, - "html_prettify": True, + "html_prettify": False, "css_minify": True, "logo_icon": "", "repo_type": "github", From 6721451915c690896ac113cb60424cc34f816d4d Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 8 Feb 2022 01:20:22 -0700 Subject: [PATCH 186/551] Make the Sphinx build error on warnings and fix all warnings (#390) * Enable nitpicky mode in the Sphinx build This will make Sphinx warn when there are cross-references that it cannot find Without it, it just silently makes the text not link to anything. * Make warnings errors in the Sphinx build There are several warnings that need to be fixed, but they are all legitimate errors in the markup that should be fixed. * Remove duplicated text * Fix all Sphinx errors from nitpicky mode A lot of errors come from autodoc wanting to make cross references for every return type hint. This is disabled manually using the nitpick_ignore variable in conf.py for each instance. --- spec/API_specification/array_object.rst | 44 +++++++++---------- .../signatures/array_object.py | 14 +++--- spec/Makefile | 2 +- spec/conf.py | 28 ++++++++++++ 4 files changed, 60 insertions(+), 28 deletions(-) diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index 8062ecd1c..9c54990f7 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -37,47 +37,47 @@ Arithmetic Operators A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. -- ``+x``: :meth:`array.__pos__` +- ``+x``: :meth:`.array.__pos__` - `operator.pos(x) `_ - `operator.__pos__(x) `_ -- `-x`: :meth:`array.__neg__` +- `-x`: :meth:`.array.__neg__` - `operator.neg(x) `_ - `operator.__neg__(x) `_ -- `x1 + x2`: :meth:`array.__add__` +- `x1 + x2`: :meth:`.array.__add__` - `operator.add(x1, x2) `_ - `operator.__add__(x1, x2) `_ -- `x1 - x2`: :meth:`array.__sub__` +- `x1 - x2`: :meth:`.array.__sub__` - `operator.sub(x1, x2) `_ - `operator.__sub__(x1, x2) `_ -- `x1 * x2`: :meth:`array.__mul__` +- `x1 * x2`: :meth:`.array.__mul__` - `operator.mul(x1, x2) `_ - `operator.__mul__(x1, x2) `_ -- `x1 / x2`: :meth:`array.__truediv__` +- `x1 / x2`: :meth:`.array.__truediv__` - `operator.truediv(x1,x2) `_ - `operator.__truediv__(x1, x2) `_ -- `x1 // x2`: :meth:`array.__floordiv__` +- `x1 // x2`: :meth:`.array.__floordiv__` - `operator.floordiv(x1, x2) `_ - `operator.__floordiv__(x1, x2) `_ -- `x1 % x2`: :meth:`array.__mod__` +- `x1 % x2`: :meth:`.array.__mod__` - `operator.mod(x1, x2) `_ - `operator.__mod__(x1, x2) `_ -- `x1 ** x2`: :meth:`array.__pow__` +- `x1 ** x2`: :meth:`.array.__pow__` - `operator.pow(x1, x2) `_ - `operator.__pow__(x1, x2) `_ @@ -89,7 +89,7 @@ Array Operators A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. -- `x1 @ x2`: :meth:`array.__matmul__` +- `x1 @ x2`: :meth:`.array.__matmul__` - `operator.matmul(x1, x2) `_ - `operator.__matmul__(x1, x2) `_ @@ -101,34 +101,34 @@ Bitwise Operators A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. -- `~x`: :meth:`array.__invert__` +- `~x`: :meth:`.array.__invert__` - `operator.inv(x) `_ - `operator.invert(x) `_ - `operator.__inv__(x) `_ - `operator.__invert__(x) `_ -- `x1 & x2`: :meth:`array.__and__` +- `x1 & x2`: :meth:`.array.__and__` - `operator.and(x1, x2) `_ - `operator.__and__(x1, x2) `_ -- `x1 | x2`: :meth:`array.__or__` +- `x1 | x2`: :meth:`.array.__or__` - `operator.or(x1, x2) `_ - `operator.__or__(x1, x2) `_ -- `x1 ^ x2`: :meth:`array.__xor__` +- `x1 ^ x2`: :meth:`.array.__xor__` - `operator.xor(x1, x2) `_ - `operator.__xor__(x1, x2) `_ -- `x1 << x2`: :meth:`array.__lshift__` +- `x1 << x2`: :meth:`.array.__lshift__` - `operator.lshift(x1, x2) `_ - `operator.__lshift__(x1, x2) `_ -- `x1 >> x2`: :meth:`array.__rshift__` +- `x1 >> x2`: :meth:`.array.__rshift__` - `operator.rshift(x1, x2) `_ - `operator.__rshift__(x1, x2) `_ @@ -140,32 +140,32 @@ Comparison Operators A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. -- `x1 < x2`: :meth:`array.__lt__` +- `x1 < x2`: :meth:`.array.__lt__` - `operator.lt(x1, x2) `_ - `operator.__lt__(x1, x2) `_ -- `x1 <= x2`: :meth:`array.__le__` +- `x1 <= x2`: :meth:`.array.__le__` - `operator.le(x1, x2) `_ - `operator.__le__(x1, x2) `_ -- `x1 > x2`: :meth:`array.__gt__` +- `x1 > x2`: :meth:`.array.__gt__` - `operator.gt(x1, x2) `_ - `operator.__gt__(x1, x2) `_ -- `x1 >= x2`: :meth:`array.__ge__` +- `x1 >= x2`: :meth:`.array.__ge__` - `operator.ge(x1, x2) `_ - `operator.__ge__(x1, x2) `_ -- `x1 == x2`: :meth:`array.__eq__` +- `x1 == x2`: :meth:`.array.__eq__` - `operator.eq(x1, x2) `_ - `operator.__eq__(x1, x2) `_ -- `x1 != x2`: :meth:`array.__ne__` +- `x1 != x2`: :meth:`.array.__ne__` - `operator.ne(x1, x2) `_ - `operator.__ne__(x1, x2) `_ diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 9098f0e2e..31a8493de 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -1,14 +1,16 @@ -from ._types import array, dtype, Optional, Tuple, Union, Any, PyCapsule, Enum, ellipsis -from ._types import device as Device +from __future__ import annotations -class array(): +from ._types import (array, dtype as Dtype, device as Device, Optional, Tuple, + Union, Any, PyCapsule, Enum, ellipsis) + +class _array(): def __init__(self) -> None: """ Initialize the attributes for the array object class. """ @property - def dtype() -> dtype: + def dtype() -> Dtype: """ Data type of the array elements. @@ -99,7 +101,7 @@ def T() -> array: Returns ------- out: array - two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array.two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. + two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. .. note:: @@ -987,3 +989,5 @@ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any .. note:: If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. """ + +array = _array diff --git a/spec/Makefile b/spec/Makefile index a82ae58bb..8082b9728 100644 --- a/spec/Makefile +++ b/spec/Makefile @@ -3,7 +3,7 @@ # You can set these variables from the command line, and also # from the environment for the first two. -SPHINXOPTS ?= +SPHINXOPTS ?= -W --keep-going SPHINXBUILD ?= sphinx-build SOURCEDIR = . BUILDDIR = _build diff --git a/spec/conf.py b/spec/conf.py index da30e54b0..5f20d1414 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -48,6 +48,34 @@ napoleon_custom_sections = [('Returns', 'params_style')] default_role = 'code' +# nitpicky = True makes Sphinx warn whenever a cross-reference target can't be +# found. +nitpicky = True +# autodoc wants to make cross-references for every type hint. But a lot of +# them don't actually refer to anything that we have a document for. +nitpick_ignore = [ + ('py:class', 'array'), + ('py:class', 'device'), + ('py:class', 'dtype'), + ('py:class', 'NestedSequence'), + ('py:class', 'SupportsBufferProtocol'), + ('py:class', 'collections.abc.Sequence'), + ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), + ('py:class', "Union[int, float, Literal[inf, - inf]]"), + ('py:class', 'PyCapsule'), + ('py:class', 'enum.Enum'), + ('py:class', 'ellipsis'), + ('py:class', 'finfo_object'), + ('py:class', 'iinfo_object'), +] +# In array_object.py we have to use aliased names for some types because they +# would otherwise refer back to method objects of array +autodoc_type_aliases = { + 'array': 'array', + 'Device': 'device', + 'Dtype': 'dtype', +} + # Make autosummary show the signatures of functions in the tables using actual # Python syntax. There's currently no supported way to do this, so we have to # just patch out the function that processes the signatures. See From a952c44599a1d0b47f622f5894a797313def9c1d Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 8 Feb 2022 19:49:03 +0000 Subject: [PATCH 187/551] Use `Sequence` from `typing` instead of `collections.abc` (#391) --- spec/API_specification/signatures/_types.py | 2 +- spec/API_specification/signatures/linalg.py | 3 +-- spec/API_specification/signatures/linear_algebra_functions.py | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/signatures/_types.py b/spec/API_specification/signatures/_types.py index 0dd899b5f..b55e8fb25 100644 --- a/spec/API_specification/signatures/_types.py +++ b/spec/API_specification/signatures/_types.py @@ -43,5 +43,5 @@ def __len__(self, /) -> int: ... __all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', -'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', +'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', 'Sequence', 'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object', 'Enum'] diff --git a/spec/API_specification/signatures/linalg.py b/spec/API_specification/signatures/linalg.py index 8a0db9c70..275fa3158 100644 --- a/spec/API_specification/signatures/linalg.py +++ b/spec/API_specification/signatures/linalg.py @@ -1,6 +1,5 @@ -from ._types import Literal, Optional, Tuple, Union, array +from ._types import Literal, Optional, Tuple, Union, Sequence, array from .constants import inf -from collections.abc import Sequence def cholesky(x: array, /, *, upper: bool = False) -> array: """ diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/spec/API_specification/signatures/linear_algebra_functions.py index a7608b9ad..d32245673 100644 --- a/spec/API_specification/signatures/linear_algebra_functions.py +++ b/spec/API_specification/signatures/linear_algebra_functions.py @@ -1,5 +1,4 @@ -from ._types import Tuple, Union, array -from collections.abc import Sequence +from ._types import Tuple, Union, Sequence, array def matmul(x1: array, x2: array, /) -> array: """ From c87257155817020266ac27b55a8fe67749d1ecc8 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 9 Nov 2021 15:46:44 +0100 Subject: [PATCH 188/551] Update DLPack structure diagram for renames in dlpack.h --- spec/_static/images/DLPack_diagram.png | Bin 31727 -> 23951 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/spec/_static/images/DLPack_diagram.png b/spec/_static/images/DLPack_diagram.png index a8459853204978f52288c4f3f74ccd1f5e30e2fb..3beadf56a9c637006d98154aa3ea7eef8c4f55ca 100644 GIT binary patch literal 23951 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 N>l(u=e!Cg Date: Tue, 9 Nov 2021 15:54:19 +0100 Subject: [PATCH 189/551] Update "scope of array API standard" figure in purpose and scope section --- spec/_static/images/scope_of_array_API.png | Bin 85530 -> 162018 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/spec/_static/images/scope_of_array_API.png b/spec/_static/images/scope_of_array_API.png index 55253288c3a266bef6f09cd6b98a6120b3eea08a..82eabadd6be28b6b42702837d83f3b4e8f9cb87e 100644 GIT binary patch literal 162018 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 literal 85530 zcmeFY`9IX}_dh;^VM3N7lr=q{Nkx(v>&V(>A7mR*5m|?_4P#o!?pY$)LY84nibQ5m zLiTM;mQZ3C`!a(W%lDz@`g;Eb-yc4|xZRp&9@n|fb*}rlpL0Kt$7Uu*`?(KugFvAD z7mf8TKp-v-5Qr@T$_adO_qE#q2!sJ$)Yr8N8k!>#6K_(27Y4z~O_{4w&W*1v4dXsP z2v(+Hz+CJwchN&ij|1=j-q?Qr;N$v-2E5Xt&MJp}8-Cv(KX3kooa^k!E@ClWVoC9( zoH()+q`;f^$n>(}_R{2s0Vh^i#Fpf^E@J*Ih3drWFWxR$cf9AVTB-q+c_47%KYw0+ z5`+u<-_H&n`hTDOKOaC}{y!i5|HlV+OA1Z1N4Mt&->PayFg|~3b3=x$&AA~@Wo^$< zt3+MnR6U8!PEI>pJ#XD~B4*!qX@^eUiC6}42>$1~yR&-lyMy85Qca?ZVh2c|2VG8D zCCCdP-T#8ZP?k1pE;h6)3+?wsFDOn)`&>l1+0XIMpFdwdzS{zc>Eyb^>!kN(G~?vUR5u3GRZUG*l>>`N8nUD*y!PNcB2bw&T@K{adjw)_df z7~nyLRaN7Cg{F&Hjfy8R(*N-S6#u)H+yJ|)WV&nI@(lABLzv@#7Yids^Kx*y#4SIE zH*`6{Xh^&N^-%ipc`@U3vpA*S(bGNu$04f$!JDf_n&QBAl~>

-6Y65T8_3_+JC! zXIFtks=x0Cc-M4R>O#Uws>uKPttnqCKS&zbg&Qe*{H>dh_&3Ef|K}MqD}y3Z%V)%0 z;|5KarY)k_{`aWuy0WxFQ=-O!(1`euJ#KGAzs&o;XV(|Pn2WtEiFJ)rN|0-4YimnQ zoJtk_Uptu0xwnc7%S%UGG#*sn=ijhN@bn-&kszHVP0=7x@rgf(*g{@*WyxSfz=8i%Bdh%bY_ z#w#_wcYF1W6YA|T2G^Fm{_hvV4uq2&v|V=Lar~6*9kMBD#WXv-Gs8KIn+27G2skJp zzu!Obj|uDFO|`ez7*SFYTOT9VW0B$p*%3tBFtXe8*&rv%u3W8yw&o$}pv}41#GtQe z=ApF%Tg(Zm@U0a3Dss1DEQ_q^KC)Q5+BrY$Q@5QGvHM}{X1ueeGiIDKKjTN3*~h=P z+SSZvrxU)l0eKL-{_P%eV|#sUjOVHOFoDPz;*sKU=mQqMInW>MxGQ^6jM-EUYH-tG zxis8g=%Z&Nw?3q9kFRc5iCpwg!l+>4|ZuwE88}%0YDn3>5HgGiA5l-4It+r)*LCiul zfR)5g6h|8ja5sS(zOgsV&T@r0|Kl%H3SaDvhK6iyH1lYPqI7ESqbZc3Y+ne7MqD4Y zKVoHYq{NU^d?zk2AMd2`0))l6_H}ngE?Rvnc}IYW6FJpwyzU$wI!Ch$?ChuZ%o0$E zVny0W1t~Dcvi5eK&SswvM%&;cB4?2`w%efExqV+}D-XYZ+wz3*Cs_gIM3lr*@taG! z@;rCT`qsS?Lp_jRs?oNEi=xs{fvx=lVJSKZe@Fa8Uj@8nmQc4Ne2O{n!sq;V<44$- z1Ik_+A~4UrQoBO{Te)B*>q>1)-hGn$9E9sNC)l0rJR(=50+eK0G%E zqH~s?Cyhxrd$F9(oP%Gb21{Tuva2JWNYrzR9!VixnJWQjlvHhJM2ko;ByXmV@p2Vf zJi^7-HszAIhbCupNgHY8C|pLujQY=a{W^7A2}dt1MKkz0pjlavX#ZmwIb#l(>DNY~ zJDZ+lNemuU(EF_OTb=2)#Z%XlHRi6**&<6Ax~LLAgsVk1hehZK8_0OT=@oiUm*vgS z32(tt@~C0x<`seRgQTseJ5S?~BO(Qh0ARzx;$u}3p$n!?1d_bqUilZCn8a)D4v zV8|Fbag$CQHb0@K(!68G8OL@LF@{iBcWfq>(tIL6c#Ld@RDqoJ&sh^-UrUafRGzmY zkfzkDxxiRZ!*az-pJk(eFL_9(`AthID=UJp_Uti#xCOYFyZ2{6{AuZ@y8XtDuG$Md z@nWsPnI5Wh+l=7VmUq?gGe%Tcy?;w8Azn|3IJKnEbygM^ahb!RMjofdAslN^0PI3Ry0xb3qlaMWfta zr?6i03AFbFum#GVI9oDZ&)czv(mxr}_`{t^(X1i{5YqFCJ*j8Zx^7FpWxlH|h}5_$pO!d~RN*XqJ+` zs<*nwIYGK%#&9!1hZ4A|spIoVbBI{gK910O9M`)z_+|NPlNsO zdu7TW%3Y?4-#j66Arw-|Ei#dol_V-1#DFht`fo<-JpC6-{W(twJ9|cIaUJKoj(eKo z_d#AdZJiiPIWH!YCi9%;1-oC!Yh-`suE~ROV^#@U!}Qy-i&+%z zrTGI;rshwm4W6Ai%J#|5$Hj%?om#uO!*3Ql*l210 zf4$xY`|Jt{`grN>;3dl7WwCVG!FSKkR*(mTj7u@joZh3015Pos`MeUaF@il04v`cf z1Wm|q08sIkD4u~9KiyL6(P|demq)3)Cvi@vhJS^g%{If8q_75t3oH&>n%xneKF^lo z|KSA(7Pdlwz^e9hxGJn_ew-kHF%8 z;^1fWj1q$^L(5aMXtE0g)FKAOXQpSn*30iWMr5;U z-CX!ZyC7JcDkHulguIpu{!P85>NwgYQIh7OOG-u z!|f~{4&`x+Z{Y6$Mu_cv4hz22#!FkN-O!|3rJ;tTAXt(S(m|0}FfmF(QU~Z=-KwCw zl>_33%GfxFJ~a&aLQ)CdmP;6;b#4r1v7E$OE3Jr!xm@k`Imc!SZ)xa)Ce4CB2Sz$4 zU{KEF%QMeeuRDz2X;S${{XbwIh_w_imLErA+IzOSR!11l-VotXifY$w;p@?R;Hy&M zpdhsp^&j*-wB<3M{7mMu@ctCbNAFtQlG0=nK4l*gXw4}gn?`BxZEbdhc5if7@#xGH zTZ1_ITKsPqOGP$?s(Hdq+w{KI3GeFU1@6#g?h~zrZkX&>N7z)>jmraWohnFqx0aL3 z?&Gb^2K}Mu$LS8no{c`R)|QMGHf}rd8|0@D@lel0F}ZjE3g_M15SQ8xXf0 zvw5E0+q{QEg=L-(ucHc%iYN!fmLrm1z&@IGpUIx+E~`23H}7(%8to&yuJ!3=hacuj zaA)A>J>>Oa2-Y@BUHmsL?R@iM7zZ&2Ibw_6ND5dud`}e6Y@0@XKjW z&bwGunp?tGJ7FkIGm$fPT3xDYJycj)&eKVSpD(-rSx#P8bz&9PPt3ybT8B})TNbsL zfr{xuMCLHf@C0iOONx$>NXX$qkIV$8-CC|&`W#c01$XUee*``M+IXrY$A3C+elfJL^i$_~CAslwD z1XD0&>Do%4f|4@MpQBNhJw{+5Z_}&P2=sKLC>krw%XO5@g%nX&)U)LU;KO8^Mx))_ zQTvDPc74Lii}hBF#7=qYHeOX6A3WV3%IHY9HE&aF#dXWni3z8z{s4uMe9-ezP}wdnvhwPrwQdJMG>k{8I=n zexfA0PEd5XhHsOJIH4CBXeC{FZ{8-J*$5m;j?q4VV{DoK!+$1VJr1H1#C#sd5ts`Q z;}xgt&q3aB{87MobWot=Xs?yEwA|vo)X1Dx8?!q?P!ogN;Ga&Ob&Y}R0�S_024 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%0D%Q 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%0A^U$Mhvo~Et2XM3t%S}s5kwT|v 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 MarsRCX&d7I0QZdV{{R30 From acf50b7de732c9d7b9b83c874c23d262966d919c Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 16 Feb 2022 10:03:35 -0800 Subject: [PATCH 190/551] Fix `axis` description in `expand_dims` (#387) --- spec/API_specification/signatures/manipulation_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/manipulation_functions.py b/spec/API_specification/signatures/manipulation_functions.py index 35e79e9d3..299625b28 100644 --- a/spec/API_specification/signatures/manipulation_functions.py +++ b/spec/API_specification/signatures/manipulation_functions.py @@ -29,7 +29,7 @@ def expand_dims(x: array, /, *, axis: int = 0) -> array: x: array input array. axis: int - axis position. Must follow Python's indexing rules: zero-based and negative indices must be counted backward from the last dimension. If ``x`` has rank ``N``, a valid ``axis`` must reside on the interval ``[-N-1, N+1]``. An ``IndexError`` exception must be raised if provided an invalid ``axis`` position. + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). An ``IndexError`` exception must be raised if provided an invalid ``axis`` position. Returns ------- From a8909061c30483d3ac080df3b4c7af18b142dafd Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 16 Feb 2022 10:04:57 -0800 Subject: [PATCH 191/551] Clarify expected results for `any` and `all` when operating on empty arrays (#388) * Clarify expected results for `any` and `all` when operating on empty arrays * Update copy --- .../signatures/utility_functions.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/spec/API_specification/signatures/utility_functions.py b/spec/API_specification/signatures/utility_functions.py index 1b0a9bf2d..79423f455 100644 --- a/spec/API_specification/signatures/utility_functions.py +++ b/spec/API_specification/signatures/utility_functions.py @@ -4,6 +4,12 @@ def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep """ Tests whether all input array elements evaluate to ``True`` along a specified axis. + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``True``. + Parameters ---------- x: array @@ -23,6 +29,12 @@ def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep """ Tests whether any input array element evaluates to ``True`` along a specified axis. + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``False``. + Parameters ---------- x: array From 3c241a257ae4145f06b379da658817db51a852c1 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 16 Feb 2022 12:09:06 -0800 Subject: [PATCH 192/551] Add `copy` kwarg support to `reshape` (#386) --- spec/API_specification/signatures/manipulation_functions.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/signatures/manipulation_functions.py b/spec/API_specification/signatures/manipulation_functions.py index 299625b28..64c05db35 100644 --- a/spec/API_specification/signatures/manipulation_functions.py +++ b/spec/API_specification/signatures/manipulation_functions.py @@ -71,7 +71,7 @@ def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: an array containing the axes permutation. The returned array must have the same data type as ``x``. """ -def reshape(x: array, /, shape: Tuple[int, ...]) -> array: +def reshape(x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None) -> array: """ Reshapes an array without changing its data. @@ -81,11 +81,13 @@ def reshape(x: array, /, shape: Tuple[int, ...]) -> array: input array to reshape. shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. + copy: Optional[bool] + boolean indicating whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. Returns ------- out: array - an output array having the same data type, elements, and underlying element order as ``x``. + an output array having the same data type and elements as ``x``. """ def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: From cc473327c387c5aa880cfa48a5cbfe775447ae97 Mon Sep 17 00:00:00 2001 From: Tirth Patel Date: Fri, 25 Feb 2022 20:00:51 +0530 Subject: [PATCH 193/551] Remove (migrated) DLPack docs from Data Interchange page (#396) --- spec/_static/images/DLPack_diagram.png | Bin 23951 -> 0 bytes spec/design_topics/data_interchange.rst | 113 ++---------------------- 2 files changed, 7 insertions(+), 106 deletions(-) delete mode 100644 spec/_static/images/DLPack_diagram.png diff --git a/spec/_static/images/DLPack_diagram.png b/spec/_static/images/DLPack_diagram.png deleted file mode 100644 index 3beadf56a9c637006d98154aa3ea7eef8c4f55ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23951 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, and hence that is what this +`DLPack `_, and hence that is what this standard has chosen as the primary/recommended protocol. Note that the ``asarray`` function also supports the Python buffer protocol (CPU-only) to support libraries that already implement buffer protocol support. @@ -70,9 +73,10 @@ support libraries that already implement buffer protocol support. See the `RFC to adopt DLPack `_ for discussion that preceded the adoption of DLPack. +DLPack's documentation can be found at: https://dmlc.github.io/dlpack/latest/. -DLPack support --------------- +The `Python specification of DLPack `__ +page gives a high-level specification for data exchange in Python using DLPack. .. note:: DLPack is a standalone protocol/project and can therefore be used outside of @@ -80,106 +84,3 @@ DLPack support are recommended to do so using the same syntax and semantics as outlined below. They are not required to return an array object from ``from_dlpack`` which conforms to this standard. - - DLPack itself has no documentation currently outside of the inline comments in - `dlpack.h `_. - In the future, the below content may be migrated to the (to-be-written) DLPack docs. - - -Syntax for data interchange with DLPack -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -The array API will offer the following syntax for data interchange: - -1. A ``from_dlpack(x)`` function, which accepts (array) objects with a - ``__dlpack__`` method and uses that method to construct a new array - containing the data from ``x``. -2. ``__dlpack__(self, stream=None)`` and ``__dlpack_device__`` methods on the - array object, which will be called from within ``from_dlpack``, to query - what device the array is on (may be needed to pass in the correct - stream, e.g. in the case of multiple GPUs) and to access the data. - - -Semantics -~~~~~~~~~ - -DLPack describe the memory layout of strided, n-dimensional arrays. -When a user calls ``y = from_dlpack(x)``, the library implementing ``x`` (the -"producer") will provide access to the data from ``x`` to the library -containing ``from_dlpack`` (the "consumer"). If possible, this must be -zero-copy (i.e. ``y`` will be a *view* on ``x``). If not possible, that library -may make a copy of the data. In both cases: - -- the producer keeps owning the memory -- ``y`` may or may not be a view, therefore the user must keep the recommendation to avoid mutating ``y`` in mind - see :ref:`copyview-mutability`. -- Both ``x`` and ``y`` may continue to be used just like arrays created in other ways. - -If an array that is accessed via the interchange protocol lives on a -device that the requesting library does not support, it is recommended to -raise a ``TypeError``. - -Stream handling through the ``stream`` keyword applies to CUDA and ROCm (perhaps -to other devices that have a stream concept as well, however those haven't been -considered in detail). The consumer must pass the stream it will use to the -producer; the producer must synchronize or wait on the stream when necessary. -In the common case of the default stream being used, synchronization will be -unnecessary so asynchronous execution is enabled. - - -Implementation -~~~~~~~~~~~~~~ - -*Note that while this API standard largely tries to avoid discussing -implementation details, some discussion and requirements are needed -here because data interchange requires coordination between -implementers on, e.g., memory management.* - -.. image:: /_static/images/DLPack_diagram.png - :alt: Diagram of DLPack structs - -*DLPack diagram. Dark blue are the structs it defines, light blue -struct members, gray text enum values of supported devices and data -types.* - -The ``__dlpack__`` method will produce a ``PyCapsule`` containing a -``DLManagedTensor``, which will be consumed immediately within -``from_dlpack`` - therefore it is consumed exactly once, and it will not be -visible to users of the Python API. - -The producer must set the ``PyCapsule`` name to ``"dltensor"`` so that -it can be inspected by name, and set ``PyCapsule_Destructor`` that calls -the ``deleter`` of the ``DLManagedTensor`` when the ``"dltensor"``-named -capsule is no longer needed. - -The consumer must transer ownership of the ``DLManangedTensor`` from the -capsule to its own object. It does so by renaming the capsule to -``"used_dltensor"`` to ensure that ``PyCapsule_Destructor`` will not get -called (ensured if ``PyCapsule_Destructor`` calls ``deleter`` only for -capsules whose name is ``"dltensor"``), but the ``deleter`` of the -``DLManagedTensor`` will be called by the destructor of the consumer -library object created to own the ``DLManagerTensor`` obtained from the -capsule. - -Note: the capsule names ``"dltensor"`` and ``"used_dltensor"`` must be -statically allocated. - -When the ``strides`` field in the ``DLTensor`` struct is ``NULL``, it indicates a -row-major compact array. If the array is of size zero, the data pointer in -``DLTensor`` should be set to either ``NULL`` or ``0``. - -DLPack version used must be ``0.2 <= DLPACK_VERSION < 1.0``. For further -details on DLPack design and how to implement support for it, -refer to `github.com/dmlc/dlpack `_. - -.. warning:: - DLPack contains a ``device_id``, which will be the device - ID (an integer, ``0, 1, ...``) which the producer library uses. In - practice this will likely be the same numbering as that of the - consumer, however that is not guaranteed. Depending on the hardware - type, it may be possible for the consumer library implementation to - look up the actual device from the pointer to the data - this is - possible for example for CUDA device pointers. - - It is recommended that implementers of this array API consider and document - whether the ``.device`` attribute of the array returned from ``from_dlpack`` is - guaranteed to be in a certain order or not. From 0603feccf60a43a2dc1e0ebe7bb51fa594fa485b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 28 Feb 2022 04:14:16 -0500 Subject: [PATCH 194/551] Fix style issues in rendered pages (#395) --- spec/API_specification/array_object.rst | 2 ++ spec/API_specification/constants.rst | 1 + spec/API_specification/searching_functions.rst | 1 + spec/API_specification/set_functions.rst | 1 + spec/API_specification/statistical_functions.rst | 1 + spec/API_specification/utility_functions.rst | 1 + spec/_templates/attribute.rst | 5 +++++ spec/_templates/property.rst | 5 +++++ 8 files changed, 17 insertions(+) create mode 100644 spec/_templates/attribute.rst create mode 100644 spec/_templates/property.rst diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index 9c54990f7..55a8ff0ab 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -256,6 +256,7 @@ Attributes .. autosummary:: :toctree: generated + :template: property.rst array.dtype array.device @@ -275,6 +276,7 @@ Methods .. autosummary:: :toctree: generated + :template: property.rst array.__abs__ array.__add__ diff --git a/spec/API_specification/constants.rst b/spec/API_specification/constants.rst index eab159c9d..aa278a360 100644 --- a/spec/API_specification/constants.rst +++ b/spec/API_specification/constants.rst @@ -17,6 +17,7 @@ Objects in API .. autosummary:: :toctree: generated + :template: attribute.rst e inf diff --git a/spec/API_specification/searching_functions.rst b/spec/API_specification/searching_functions.rst index 18289466a..b8a2b39a5 100644 --- a/spec/API_specification/searching_functions.rst +++ b/spec/API_specification/searching_functions.rst @@ -23,6 +23,7 @@ Objects in API .. autosummary:: :toctree: generated + :template: method.rst argmax argmin diff --git a/spec/API_specification/set_functions.rst b/spec/API_specification/set_functions.rst index 1f287fece..4ba2ad424 100644 --- a/spec/API_specification/set_functions.rst +++ b/spec/API_specification/set_functions.rst @@ -19,6 +19,7 @@ Objects in API .. autosummary:: :toctree: generated + :template: method.rst unique_all unique_counts diff --git a/spec/API_specification/statistical_functions.rst b/spec/API_specification/statistical_functions.rst index 68e6830e2..d87f5d25a 100644 --- a/spec/API_specification/statistical_functions.rst +++ b/spec/API_specification/statistical_functions.rst @@ -22,6 +22,7 @@ Objects in API .. autosummary:: :toctree: generated + :template: method.rst max mean diff --git a/spec/API_specification/utility_functions.rst b/spec/API_specification/utility_functions.rst index 2a9f411bf..887819194 100644 --- a/spec/API_specification/utility_functions.rst +++ b/spec/API_specification/utility_functions.rst @@ -22,6 +22,7 @@ Objects in API .. autosummary:: :toctree: generated + :template: method.rst all any diff --git a/spec/_templates/attribute.rst b/spec/_templates/attribute.rst new file mode 100644 index 000000000..30d21295b --- /dev/null +++ b/spec/_templates/attribute.rst @@ -0,0 +1,5 @@ +.. currentmodule:: {{ module }} + +{{ name.split('.')[-1] | underline }} + +.. autodata:: {{ name }} diff --git a/spec/_templates/property.rst b/spec/_templates/property.rst new file mode 100644 index 000000000..baf31cea3 --- /dev/null +++ b/spec/_templates/property.rst @@ -0,0 +1,5 @@ +.. currentmodule:: {{ module }} + +{{ name.split('.')[-1] | underline }} + +.. auto{{ objtype }}:: {{ objname }} \ No newline at end of file From 157c16ba5b72b82b5486b8efeb00cb6744b181c5 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 28 Feb 2022 01:16:50 -0800 Subject: [PATCH 195/551] Restrict `linspace` support to floating-point data types (#393) * Restrict support to floating-point data types * Remove linebreak --- spec/API_specification/signatures/creation_functions.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index 0cb199850..39692e471 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -14,7 +14,7 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None step: Union[int, float] the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default floating-point data type. Default: ``None``. + output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. @@ -22,6 +22,12 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None .. note:: This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. + .. note:: + While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + + .. note:: + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + Returns ------- out: array From 50a70af66c4e61e8927661523fe8ecb6f8b40a02 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 3 Mar 2022 16:16:15 -0500 Subject: [PATCH 196/551] Update to rst and create fft functions stubs --- .../signatures/fourier_transform_functions.py | 424 +++++++++++++++ .../extensions/fourier_transform_functions.md | 505 ------------------ .../fourier_transform_functions.rst | 40 ++ 3 files changed, 464 insertions(+), 505 deletions(-) create mode 100644 spec/API_specification/signatures/fourier_transform_functions.py delete mode 100644 spec/extensions/fourier_transform_functions.md create mode 100644 spec/extensions/fourier_transform_functions.rst diff --git a/spec/API_specification/signatures/fourier_transform_functions.py b/spec/API_specification/signatures/fourier_transform_functions.py new file mode 100644 index 000000000..ada43e593 --- /dev/null +++ b/spec/API_specification/signatures/fourier_transform_functions.py @@ -0,0 +1,424 @@ +from ._types import Tuple, Union, Sequence, array, Optional + + +def fft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: + """ + Computes the one-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifft(fft(a)) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + n: int + length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length ``n`` before computing the Fourier transform. Otherwise, the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + axis: int + axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: No normalization. + - ``'ortho'``: Normalize by ``1/sqrt(n)``. + - ``'forward'``: Normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. + + + **Raises** + + - If ``axis`` is not a valid axis of ``a``. + """ + + +def ifft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifft(fft(a)) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + n: int + length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length ``n`` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + axis: int + axis used to compute the inverse Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: Normalize by ``1/n``. + - ``'ortho'``: Normalize by ``1/sqrt(n)`` + - ``'forward'``: No normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. + + + **Raises** + + - If ``axis`` is not a valid axis of ``a``. + """ + + +def fftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: + """ + Computes the n-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifftn(fftn(a)) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + s: Union[Sequence[int], Tuple[int, ...]] + size of each transformed axis of the output. If given, each axis ``i`` will be either zero-padded or trimmed to the length ``s[i]`` before computing the Fourier transform. Otherwise, the shape of the input along the axes given by the ``axes`` keyword. Default: ``None``. + axes: Union[Sequence[int], Tuple[int, ...]] + axes over which to compute the Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: No normalization. + - ``'ortho'``: Normalize by ``1/sqrt(n)``. + - ``'forward'``: Normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes indicated by the ``axes`` keyword. + + + **Raises** + + - If ``s`` and ``axes`` have different lengths. + - If ``axes`` contains any invalid axis of ``a``. + """ + + +def ifftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: + """ + Computes the n-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifftn(fftn(a)) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + s: Union[Sequence[int], Tuple[int, ...]] + size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length ``s[i]`` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the ``axes`` keyword. Default: ``None``. + axes: Union[Sequence[int], Tuple[int, ...]] + axes over which to compute the inverse Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: Normalize by ``1/n``. + - ``'ortho'``: Normalize by ``1/sqrt(n)`` + - ``'forward'``: No normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes indicated by the `axes` keyword. + + + **Raises** + + - If ``s`` and ``axes`` have different lengths. + - If ``axes`` contains any invalid axis of ``a``. + """ + + +def rfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: + """ + Computes the one-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, ``irfft(rfft(a), n=a.shape[axis]) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + n: int + length of the transformed axis of the **input**. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the ``axis`` keyword is used. Default: ``None``. + axis: int + axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: No normalization. + - ``'ortho'``: Normalize by ``1/sqrt(n)``. + - ``'forward'``: Normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. + + + **Raises** + + - If ``axis`` is not a valid axis of ``a``. + """ + + +def irfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: + """ + Computes the one-dimensional inverse of ``rfft``. The expected behavior includes a round-trip transform using the inverse function, ``irfft(rfft(a), n=a.shape[axis]) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + n: int + length of the transformed axis of the **output**. If given, the input will be either zero-padded or trimmed to ``n//2+1`` before computing the inverse of ``rfft``. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + axis: int + axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: Normalize by ``1/n``. + - ``'ortho'``: Normalize by ``1/sqrt(n)`` + - ``'forward'``: No normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + a real-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n`` (if given) or ``2 * (m - 1)``. + + + **Raises** + + - If ``axis`` is not a valid axis of ``a``. + """ + + +def rfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: + """ + Computes the n-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, ``irfftn(rfftn(a), s=a.shape) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + s: Union[Sequence[int], Tuple[int, ...]] + size of each transformed axis of the output. If given, each axis ``i`` will be either zero-padded or trimmed to the length ``s[i]`` before computing the real Fourier transform. Otherwise, the shape of the input along the axes given by the `axes` keyword. The last element ``s[-1]`` is for computing ``rfft(a[axes[-1]], n=s[-1])`` whereas other elements for ``fft(a[axes[i]], n=s[i])``. Default: ``None``. + axes: Union[Sequence[int], Tuple[int, ...]] + axes over which to compute the Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: No normalization. + - ``'ortho'``: Normalize by ``1/sqrt(n)``. + - ``'forward'``: Normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + a complex-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]//2+1`` and along other axes ``s[i]``. + + + **Raises** + + - If ``s`` and ``axes`` have different lengths. + - If ``axes`` contains any invalid axis of ``a``. + """ + + +def irfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: + """ + Computes the n-dimensional inverse of ``rfftn``. The expected behavior includes a round-trip transform using the inverse function, ``irfftn(rfftn(a), s=a.shape) == a`` within numerical accuracy. + + Parameters + ---------- + a: array + input array + s: Union[Sequence[int], Tuple[int, ...]] + size of each transformed axis of the **output**. If given, the last axis will be either zero-padded or trimmed to ``s[-1]//2+1``, whereas all other axes ``i`` are either zero-padded or trimmed to the length ``s[i]``, before computing the inverse of ``rfftn``. Otherwise, the last axis is either zero-padded or trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis, and all other axes use the input shape. The last element ``s[-1]`` is for computing ``irfft(a[axes[-1]], n=s[-1])`` whereas other elements for ``ifft(a[axes[i]], n=s[i])``. Default: ``None``. + axes: Union[Sequence[int], Tuple[int, ...]] + axes over which to compute the inverse Fourier transform. If it is not specified, the last ``len(s)`` axes are used or all axes if ``s`` is also not specified. Default: ``None``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: Normalize by ``1/n``. + - ``'ortho'``: Normalize by ``1/sqrt(n)`` + - ``'forward'``: No normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + a real-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. + + + **Raises** + + - If ``s`` and ``axes`` have different lengths. + - If ``axes`` contains any invalid axis of ``a``. + """ + + +def hfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: + """ + Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + a: array + input array + n: int + length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + axis: int + axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: No normalization. + - ``'ortho'``: Normalize by ``1/sqrt(n)``. + - ``'forward'``: Normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + a transformed array. + + + **Raises** + + - If ``axis`` is not a valid axis of ``a``. + """ + + +def ihfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + a: array + input array + n: int + length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + axis: int + axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. + norm: str + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: Normalize by ``1/n``. + - ``'ortho'``: Normalize by ``1/sqrt(n)`` + - ``'forward'``: No normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + a transformed array. + + + **Raises** + + - If ``axis`` is not a valid axis of ``a``. + """ + + +def fftfreq(n: int, /, *, d: float = 1.0): + """ + Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + + + .. code-block:: + + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + + Returns + ------- + out: array + an array of length ``n`` containing the sample frequencies. + """ + + +def rfftfreq(n: int, /, *, d: float = 1.0): + """ + Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + + + .. code-block:: + + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd + + The Nyquist frequency component is considered to be positive. + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + + Returns + ------- + out: array + an array of length ``n`` containing the sample frequencies. + """ + + +def fftshift(x: array, /, *, axes: Union[int, Sequence[int], Tuple[int, ...]] = None): + """ + Reorders n-dimensional FTT data to have negative frequency terms first. In this way, the zero-frequency component shifts to the center of the spectrum. Note that ``out[0]`` is the Nyquist component only if the length of the input is even. + + Parameters + ---------- + x: array + input array. + axes: Union[int, Sequence[int], Tuple[int, ...]] + axes over which to shift. If not specified, it shifts all axes. Default: ``None``. + + Returns + ------- + out: array + the shifted array. + """ + + +def ifftshift(x: array, /, *, axes: Union[int, Sequence[int], Tuple[int, ...]] = None): + """ + Inverse of ``fftshift``. + + Parameters + ---------- + x: array + input array. + axes: Union[int, Sequence[int], Tuple[int, ...]] + axes over which to calculate. If not specified, it shifts all axes. Default: ``None``. + + Returns + ------- + out: array + the shifted array. + """ + + +__all__ = ['fft','ifft','fftn','ifftn','rfft','irfft','rfftn','irfftn','hfft','ihfft','fftfreq','rfftfreq','fftshift','ifftshift'] \ No newline at end of file diff --git a/spec/extensions/fourier_transform_functions.md b/spec/extensions/fourier_transform_functions.md deleted file mode 100644 index 51fb34c82..000000000 --- a/spec/extensions/fourier_transform_functions.md +++ /dev/null @@ -1,505 +0,0 @@ -# Fourier transform Functions - -> Array API specification for Fourier transform functions. - -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](https://www.python.org/dev/peps/pep-0570/) 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](https://www.python.org/dev/peps/pep-3102/) 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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - -## Objects in API - - -(function-fft)= -### fft(a, /, *, n=None, axis=-1, norm='backward') - -Computes the one-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifft(fft(a)) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **n**: _int_ - - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the Fourier transform. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. - -- **axis**: _int_ - - - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A complex-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n//2+1`. - -#### Raises - -- If `axis` is not a valid axis of `a`. - -(function-ifft)= -### ifft(a, /, *, n=None, axis=-1, norm='backward') - -Computes the one-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifft(fft(a)) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **n**: _int_ - - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length `n` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the `axis` keyword. Default: `None`. - -- **axis**: _int_ - - - Axis used to compute the inverse Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: Normalize by `1/n`. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A complex-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n//2+1`. - -#### Raises - -- If `axis` is not a valid axis of `a`. - -(function-fftn)= -### fftn(a, /, *, s=None, axes=None, norm='backward') - -Computes the n-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifftn(fftn(a)) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Size of each transformed axis of the output. If given, each axis `i` will be either zero-padded or trimmed to the length `s[i]` before computing the Fourier transform. Otherwise, the shape of the input along the axes given by the `axes` keyword. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to compute the Fourier transform. If not specified, the last `len(s)` axes are used, or all axes if `s` is not specified either. Default: `None`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - An array transformed along the axes indicated by the `axes` keyword. - -#### Raises - -- If `s` and `axes` have different lengths. -- If `axes` contains any invalid axis of `a`. - -(function-ifftn)= -### ifftn(a, /, *, s=None, axes=None, norm='backward') - -Computes the n-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, `ifftn(fftn(a)) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length `s[i]` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the `axes` keyword. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to compute the inverse Fourier transform. If not specified, the last `len(s)` axes are used, or all axes if `s` is not specified either. Default: `None`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: Normalize by `1/n`. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - An array transformed along the axes indicated by the `axes` keyword. - -#### Raises - -- If `s` and `axes` have different lengths. -- If `axes` contains any invalid axis of `a`. - -(function-rfft)= -### rfft(a, /, *, n=None, axis=-1, norm='backward') - -Computes the one-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, `irfft(rfft(a), n=a.shape[axis]) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **n**: _int_ - - - Length of the transformed axis of the *input*. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the `axis` keyword is used. Default: `None`. - -- **axis**: _int_ - - - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A complex-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n//2+1`. - -#### Raises - -- If `axis` is not a valid axis of `a`. - -(function-irfft)= -### irfft(a, /, *, n=None, axis=-1, norm='backward') - -Computes the one-dimensional inverse of `rfft`. The expected behavior includes a round-trip transform using the inverse function, `irfft(rfft(a), n=a.shape[axis]) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **n**: _int_ - - - Length of the transformed axis of the *output*. If given, the input will be either zero-padded or trimmed to `n//2+1` before computing the inverse of `rfft`. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - -- **axis**: _int_ - - - Axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: Normalize by `1/n`. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A real-valued array transformed along the axis indicated by the `axis` keyword. The length along the transformed axis is `n` (if given) or `2 * (m - 1)`. - -#### Raises - -- If `axis` is not a valid axis of `a`. - -(function-rfftn)= -### rfftn(a, /, *, s=None, axes=None, norm='backward') - -Computes the n-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, `irfftn(rfftn(a), s=a.shape) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Size of each transformed axis of the output. If given, each axis `i` will be either zero-padded or trimmed to the length `s[i]` before computing the real Fourier transform. Otherwise, the shape of the input along the axes given by the `axes` keyword. The last element `s[-1]` is for computing `rfft(a[axes[-1]], n=s[-1])` whereas other elements for `fft(a[axes[i]], n=s[i])`. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to compute the Fourier transform. If not specified, the last `len(s)` axes are used, or all axes if `s` is not specified either. Default: `None`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A complex-valued array transformed along the axes indicated by the `axes` keyword. The length along the last transformed axis is `s[-1]//2+1` and along other axes `s[i]`. - -#### Raises - -- If `s` and `axes` have different lengths. -- If `axes` contains any invalid axis of `a`. - -(function-irfftn)= -### irfftn(a, /, *, s=None, axes=None, norm='backward') - -Computes the n-dimensional inverse of `rfftn`. The expected behavior includes a round-trip transform using the inverse function, `irfftn(rfftn(a), s=a.shape) == a` within numerical accuracy. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **s**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Size of each transformed axis of the *output*. If given, the last axis will be either zero-padded or trimmed to `s[-1]//2+1`, whereas all other axes `i` are either zero-padded or trimmed to the length `s[i]`, before computing the inverse of `rfftn`. Otherwise, the last axis is either zero-padded or trimmed to `2 * (m - 1)`, where `m` is the length of the input along the axis, and all other axes use the input shape. The last element `s[-1]` is for computing `irfft(a[axes[-1]], n=s[-1])` whereas other elements for `ifft(a[axes[i]], n=s[i])`. Default: `None`. - -- **axes**: _Union\[ Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to compute the inverse Fourier transform. If it is not specified, the last `len(s)` axes are used or all axes if `s` is also not specified. Default: `None`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: Normalize by `1/n`. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A real-valued array transformed along the axes indicated by the `axes` keyword. The length along the last transformed axis is `s[-1]` (if given) or `2 * (m - 1)`, and all other axes `s[i]`. - -#### Raises - -- If `s` and `axes` have different lengths. -- If `axes` contains any invalid axis of `a`. - -(function-hfft)= -### hfft(a, /, *, n=None, axis=-1, norm='backward') - -Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **n**: _int_ - - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - -- **axis**: _int_ - - - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: No normalization. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: Normalize by `1/n`. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A transformed array. - -#### Raises - -- If `axis` is not a valid axis of `a`. - -(function-ihfft)= -### ihfft(a, /, *, n=None, axis=-1, norm='backward') - -Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. - -#### Parameters - -- **a**: _<array>_ - - - Input array. - -- **n**: _int_ - - - Length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to `2 * (m - 1)` where `m` is the length of the input along the axis given by the `axis` keyword. Default: `None`. - -- **axis**: _int_ - - - Axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: `-1`. - -- **norm**: _str_ - - - Specify the normalization mode. Should be one of the following modes: - - - `'backward'`: Normalize by `1/n`. - - `'ortho'`: Normalize by `1/sqrt(n)` - - `'forward'`: No normalization. - - Default: `'backward'` - -#### Returns - -- **out**: _<array>_ - - - A transformed array. - -#### Raises - -- If `axis` is not a valid axis of `a`. - -(function-fftfreq)= -### fftfreq(n, /, *, d=1.0) - -Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length `n` and length unit of `d` the frequencies are described as: - -``` -f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even -f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd -``` - -#### Parameters - -- **n**: _int_ - - - Window length. - -- **d**: _float_ - - - Sample spacing between individual samples of the Fourier transform input. Default: `1.0`. - -#### Returns - -- **out**: _<array>_ - - - An array of length `n` containing the sample frequencies. - -(function-rfftfreq)= -### rfftfreq(n, /, *, d=1.0) - -Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length `n` and length unit of `d` the frequencies are described as: - -``` -f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even -f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd -``` - -The Nyquist frequency component is considered to be positive. - -#### Parameters - -- **n**: _int_ - - - Window length. - -- **d**: _float_ - - - Sample spacing between individual samples of the Fourier transform input. Default: `1.0`. - -#### Returns - -- **out**: _<array>_ - - - An array of length `n` containing the sample frequencies. - -(function-fftshift)= -### fftshift(x, /, *, axes=None) - -Reorders n-dimensional FTT data to have negative frequency terms first. In this way, the zero-frequency component shifts to the center of the spectrum. Note that `out[0]` is the Nyquist component only if the length of the input is even. - -#### Parameters - -- **x**: _<array>_ - - - Input array. - -- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to shift. If not specified, it shifts all axes. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - The shifted array. - -(function-ifftshift)= -### ifftshift(x, /, *, axes=None) - -Inverse of `fftshift`. - -#### Parameters - -- **x**: _<array>_ - - - Input array. - -- **axes**: _Union\[ int, Sequence\[ int ], Tuple\[ int, ... ] ]_ - - - Axes over which to calculate. If not specified, it shifts all axes. Default: `None`. - -#### Returns - -- **out**: _<array>_ - - - The shifted array. diff --git a/spec/extensions/fourier_transform_functions.rst b/spec/extensions/fourier_transform_functions.rst new file mode 100644 index 000000000..4859c7d0c --- /dev/null +++ b/spec/extensions/fourier_transform_functions.rst @@ -0,0 +1,40 @@ +Fourier transform Functions +=========================== + + Array API specification for Fourier transform functions. + +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`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. + +Objects in API +-------------- + +.. currentmodule:: signatures.fourier_transform_functions + +.. + NOTE: please keep the functions and their inverse together + +.. autosummary:: + :toctree: generated + :template: method.rst + + fft + ifft + fftn + ifftn + rfft + irfft + rfftn + irfftn + hfft + ihfft + fftfreq + rfftfreq + fftshift + ifftshift From c16f5fadd9df2ebe420b68102e7f6ff19d6eb6ee Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 21 Mar 2022 00:57:52 -0700 Subject: [PATCH 197/551] Update the specification for `remainder` to include special cases for floating-point operands (#401) * Specify special cases for floating-point operands * Document dunder method * Update note * Fix indentation Co-authored-by: Matthew Barber * Fix indentation Co-authored-by: Matthew Barber * Fix spelling Co-authored-by: Matthew Barber * Lowercase heading Co-authored-by: Matthew Barber Co-authored-by: Matthew Barber --- .../signatures/array_object.py | 28 +++++++++++++++ .../signatures/elementwise_functions.py | 34 ++++++++++++++++++- 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 31a8493de..970f641a1 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -634,6 +634,34 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + **Special Cases** + + .. note:: + In general, this method is **not** recommended for floating-point operands as semantics do not follow IEEE 754. That this method is specified to accept floating-point operands is primarily for reasons of backward compatibility. + + For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x2_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - In the remaining cases, the result must match that of the Python ``%`` operator. + Parameters ---------- self: array diff --git a/spec/API_specification/signatures/elementwise_functions.py b/spec/API_specification/signatures/elementwise_functions.py index 0abb852d1..e14b213c8 100644 --- a/spec/API_specification/signatures/elementwise_functions.py +++ b/spec/API_specification/signatures/elementwise_functions.py @@ -638,7 +638,7 @@ def floor_divide(x1: array, x2: array, /) -> array: - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. Parameters ---------- @@ -1112,9 +1112,40 @@ def remainder(x1: array, x2: array, /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. + .. note:: + This function is equivalent to the Python modulus operator ``x1_i % x2_i``. + .. note:: For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + **Special cases** + + .. note:: + In general, similar to Python's ``%`` operator, this function is **not** recommended for floating-point operands as semantics do not follow IEEE 754. That this function is specified to accept floating-point operands is primarily for reasons of backward compatibility. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x2_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - In the remaining cases, the result must match that of the Python ``%`` operator. + Parameters ---------- x1: array @@ -1206,6 +1237,7 @@ def sinh(x: array, /) -> array: Calculates an implementation-dependent approximation to the hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. **Special cases** + For floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. From 02fa9237eab3258120778baec12cd38cfd309ee3 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 23 Mar 2022 11:59:36 +0000 Subject: [PATCH 198/551] Make `logaddexp()` arguments pos-only (#406) --- spec/API_specification/signatures/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/elementwise_functions.py b/spec/API_specification/signatures/elementwise_functions.py index e14b213c8..52488f970 100644 --- a/spec/API_specification/signatures/elementwise_functions.py +++ b/spec/API_specification/signatures/elementwise_functions.py @@ -870,7 +870,7 @@ def log10(x: array, /) -> array: an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ -def logaddexp(x1: array, x2: array) -> array: +def logaddexp(x1: array, x2: array, /) -> array: """ Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. From cc94ea197326fab79795a2b8a021d4ca2e11376a Mon Sep 17 00:00:00 2001 From: Chris <14341145+cnpryer@users.noreply.github.com> Date: Mon, 28 Mar 2022 09:58:04 -0400 Subject: [PATCH 199/551] Fix typo in purpose and scope history section (#412) --- spec/purpose_and_scope.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index 6e19c02ea..fc8433c7f 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -60,7 +60,7 @@ learning, many other libraries have appeared, leading to more severe fragmentation. Concepts and APIs in newer libraries were often inspired by (or copied from) those in older ones - and then changed or improved upon to fit new needs and use cases. Individual library authors discussed ideas, -however there was never (before this array API standard) an serious attempt +however there was never (before this array API standard) a serious attempt to coordinate between all libraries to avoid fragmentation and arrive at a common API standard. From 93f8d35cee59a5cebda386c4d9a38cef422cca06 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 5 Apr 2022 23:29:00 +0100 Subject: [PATCH 200/551] `expm1` should having float inputs (#413) --- spec/API_specification/signatures/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/elementwise_functions.py b/spec/API_specification/signatures/elementwise_functions.py index 52488f970..213ebe53e 100644 --- a/spec/API_specification/signatures/elementwise_functions.py +++ b/spec/API_specification/signatures/elementwise_functions.py @@ -562,7 +562,7 @@ def expm1(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a floating-point data type. Returns ------- From c58051748090fe97aae980837c63c02c5e405ff2 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 6 Apr 2022 20:37:55 -0700 Subject: [PATCH 201/551] Clarify overflow behavior in `asarray` (#409) * Add note concerning overflow in `asarray` * Update notes * Update note --- spec/API_specification/signatures/creation_functions.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index 39692e471..7c46aafac 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -62,6 +62,9 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`signatures.data_type_functions.astype`. + .. note:: + If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. + device: Optional[device] device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. copy: Optional[bool] @@ -168,7 +171,7 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value``. If the fill value is an ``int``, the output array data type must be the default integer data type. If the fill value is a ``float``, the output array data type must be the default floating-point data type. If the fill value is a ``bool``, the output array must have boolean data type. Default: ``None``. .. note:: - If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + If the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. device: Optional[device] device on which to place the created array. Default: ``None``. @@ -193,10 +196,10 @@ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dty output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. .. note:: - If ``dtype`` is ``None`` and the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + If the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. .. note:: - If ``dtype`` is ``None`` and the ``fill_value`` has a data type (``int`` or ``float``) which is not of the same data type kind as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + If the ``fill_value`` has a data type (``int`` or ``float``) which is not of the same data type kind as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. device: Optional[device] device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. From 6c49f50307fb25e111e87b99ba8f7a1de4acd2af Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 17 Apr 2022 22:57:47 -0700 Subject: [PATCH 202/551] Add support for expanding dimensions using `None` (#408) * Add support for expanding dimensions using `None` * Clarify guidance when using `None` incombination with other indexing expressions * Clarify language * Clarify exception guidance * Revert markup changes --- spec/API_specification/indexing.rst | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/indexing.rst b/spec/API_specification/indexing.rst index 889517ca6..13fe70a3f 100644 --- a/spec/API_specification/indexing.rst +++ b/spec/API_specification/indexing.rst @@ -137,7 +137,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Providing a single negative integer ``i`` as a single-axis index must index the same elements as the slice ``n+i:n+i+1``, where ``n`` is the axis (dimension) size. -- Providing a single integer as a single-axis index must reduce the number of array dimensions by ``1`` (i.e., the array rank should decrease by one; if ``A`` has rank ``2``, ``rank(A)-1 == rank(A[0, :])``). In particular, a selection tuple with the ``m``\th element an integer (and all other entries ``:``) indexes a sub-array with rank ``N-1``. +- Providing a single integer as a single-axis index must reduce the number of array dimensions by ``1`` (i.e., the array rank must decrease by one; if ``A`` has rank ``2``, ``rank(A)-1 == rank(A[0, :])``). In particular, a selection tuple with the ``m``\th element an integer (and all other entries ``:``) indexes a sub-array with rank ``N-1``. .. note:: When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. @@ -151,14 +151,19 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult .. note:: This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. -- Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions is less than ``N``. +- Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. + + .. note:: + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + +- Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. .. note:: Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. To perform flat indexing, use ``reshape(x, (-1,))[integer]``. -- An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions is greater than ``N``. +- An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions (excluding ``None``) is greater than ``N``. .. note:: This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. @@ -175,6 +180,9 @@ Boolean Array Indexing An array must support indexing where the **sole index** is an ``M``-dimensional boolean array ``B`` with shape ``S1 = (s1, ..., sM)`` according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S2 = (s1, ..., sM, ..., sN)``. + .. note:: + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + - If ``N >= M``, then ``A[B]`` must replace the first ``M`` dimensions of ``A`` with a single dimension having a size equal to the number of ``True`` elements in ``B``. The values in the resulting array must be in row-major (C-style order); this is equivalent to ``A[nonzero(B)]``. .. note:: From 77b66c1eb15321e21d72afa824c63745d6db722a Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 17 Apr 2022 23:05:45 -0700 Subject: [PATCH 203/551] Add `newaxis` constant for use in array indexing (#414) * Add `newaxis` constant * Update ToC --- spec/API_specification/constants.rst | 1 + spec/API_specification/signatures/constants.py | 7 ++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/constants.rst b/spec/API_specification/constants.rst index aa278a360..4d71ed380 100644 --- a/spec/API_specification/constants.rst +++ b/spec/API_specification/constants.rst @@ -22,4 +22,5 @@ Objects in API e inf nan + newaxis pi diff --git a/spec/API_specification/signatures/constants.py b/spec/API_specification/signatures/constants.py index 813b6d079..18c8ac761 100644 --- a/spec/API_specification/signatures/constants.py +++ b/spec/API_specification/signatures/constants.py @@ -15,6 +15,11 @@ IEEE 754 floating-point representation of Not a Number (``NaN``). """ +newaxis = None +""" +An alias for ``None`` which is useful for indexing arrays. +""" + pi = 3.141592653589793 """ IEEE 754 floating-point representation of the mathematical constant ``π``. @@ -22,4 +27,4 @@ ``pi = 3.1415926535897932384626433...`` """ -__all__ = ['e', 'inf', 'nan', 'pi'] +__all__ = ['e', 'inf', 'nan', 'newaxis', 'pi'] From c5808f2b173ea52d813c450bec7b1beaf2973299 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 21 Apr 2022 05:02:48 -0500 Subject: [PATCH 204/551] Fix tensordot broadcasting rules (#419) * Fix tensordot broadcasting rules The noncontracted axes do not broadcast together and do not need to be broadcast compatible. * Replace a "should" with "must" --- spec/API_specification/signatures/linear_algebra_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/spec/API_specification/signatures/linear_algebra_functions.py index d32245673..30d09c254 100644 --- a/spec/API_specification/signatures/linear_algebra_functions.py +++ b/spec/API_specification/signatures/linear_algebra_functions.py @@ -61,7 +61,7 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], x1: array first input array. Should have a numeric data type. x2: array - second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Should have a numeric data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. .. note:: Contracted axes (dimensions) must not be broadcasted. From 416b71a24c3f6cdedb9bbd4b29bf4a3fee071910 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 25 Apr 2022 11:08:57 -0700 Subject: [PATCH 205/551] Fix erroneous updates to arange intended for linspace (#421) * Fix erroneous updates to arange intended for linspace * Add linebreak * Fix indentation * Add linebreaks Co-authored-by: Matthew Barber Co-authored-by: Matthew Barber --- .../signatures/creation_functions.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index 7c46aafac..88db02340 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -14,7 +14,7 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None step: Union[int, float] the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. dtype: Optional[dtype] - output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. @@ -22,12 +22,6 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None .. note:: This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. - .. note:: - While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. - - .. note:: - As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. - Returns ------- out: array @@ -227,7 +221,7 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, num: int number of samples. Must be a non-negative integer value; otherwise, the function must raise an exception. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. endpoint: bool @@ -237,6 +231,13 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, ------- out: array a one-dimensional array containing evenly spaced values. + + + .. note:: + While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + + .. note:: + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. """ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: From 4c134fe8fd780da0c99e4330c92f9aee6e1c81a3 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 2 May 2022 01:51:00 -0700 Subject: [PATCH 206/551] Add admonition concerning array view mutation (#420) * Add admonition concerning array view mutation * Update admonition --- spec/design_topics/copies_views_and_mutation.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/design_topics/copies_views_and_mutation.rst b/spec/design_topics/copies_views_and_mutation.rst index 2ed3d8e41..52be1c805 100644 --- a/spec/design_topics/copies_views_and_mutation.rst +++ b/spec/design_topics/copies_views_and_mutation.rst @@ -3,6 +3,11 @@ Copy-view behaviour and mutability ================================== +.. admonition:: Mutating views + :class: important + + Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may be either a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. + Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically have the concept of a "view", meaning an array containing data in memory that belongs to another array (i.e. a different "view" on the original data). @@ -70,6 +75,3 @@ of reusing arrays that are no longer needed as buffers. This leaves the problem of the initial example - with this API standard it remains possible to write code that will not work the same for all array libraries. This is something that the user must be careful about. - -.. note:: - It is recommended that users avoid any mutating operations when a view may be involved. From 3ff72cf19d64233225c9293f1303a60412446e07 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 2 May 2022 02:57:29 -0600 Subject: [PATCH 207/551] Add a version menu to the Sphinx build (#394) * Fix warnings in the Sphinx build * Include the version number in the header * Enable the version dropdown menu To make this work, a versions.json file will need to be added to the root of the gh-pages branch, which is a dict mapping "label": "path" for each version. This should be updated whenever a new version is tagged. --- spec/conf.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/conf.py b/spec/conf.py index 5f20d1414..493b01477 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -62,6 +62,8 @@ ('py:class', 'collections.abc.Sequence'), ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), ('py:class', "Union[int, float, Literal[inf, - inf]]"), + ('py:obj', "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]"), + ('py:obj', "typing.Union[int, float, typing.Literal[inf, - inf]]"), ('py:class', 'PyCapsule'), ('py:class', 'enum.Enum'), ('py:class', 'ellipsis'), @@ -123,7 +125,7 @@ html_theme_options = { # Set the name of the project to appear in the navigation. - 'nav_title': 'Python array API standard', + 'nav_title': f'Python array API standard {release}', # Set you GA account ID to enable tracking #'google_analytics_account': 'UA-XXXXX', @@ -170,8 +172,8 @@ #"customization": "Configuration options to personalize your site.", }, - #"version_dropdown": True, - #"version_json": "_static/versions.json", + "version_dropdown": True, + "version_json": "../versions.json", "table_classes": ["plain"], } From 02cdbb8714ff4164ce415367c41b2e4be287a640 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 02:20:27 -0700 Subject: [PATCH 208/551] Update release version --- spec/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/conf.py b/spec/conf.py index 493b01477..33fccbca8 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -22,7 +22,7 @@ author = 'Consortium for Python Data API Standards' # The full version, including alpha/beta/rc tags -release = '2021.01-DRAFT' +release = '2021.12' # -- General configuration --------------------------------------------------- From 81dfe859221f76cd959e0b6ea7d3bf816bdaab71 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 02:30:47 -0700 Subject: [PATCH 209/551] Update version to 2022 --- spec/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/conf.py b/spec/conf.py index 33fccbca8..bbb2f5d1d 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -22,7 +22,7 @@ author = 'Consortium for Python Data API Standards' # The full version, including alpha/beta/rc tags -release = '2021.12' +release = '2022.05-DRAFT' # -- General configuration --------------------------------------------------- From cde11b310af286e9fa8ca05db226f691ed44d5d6 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 03:42:27 -0700 Subject: [PATCH 210/551] Update gitignore --- .gitignore | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/.gitignore b/.gitignore index 0ca7c019e..73e203a64 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,29 @@ +#/ +# @license MIT +# +# Copyright (c) 2022 Python Data APIs Consortium. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#/ + spec/_build/ +doctrees/ build/ .vscode/ node_modules/ From f31af47a454540947cd736cf85be34e1a197661b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 03:42:50 -0700 Subject: [PATCH 211/551] Clean-up workflow --- .github/workflows/pages.yml | 125 +++++++++++++++++++++++++++--------- 1 file changed, 95 insertions(+), 30 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 67bafdb25..4ea7dca8b 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -1,39 +1,104 @@ +#/ +# @license MIT +# +# Copyright (c) 2022 Python Data APIs Consortium. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#/ + +# Workflow name: +name: gh_pages + +# Workflow triggers: on: push: branches: - main + pull_request: branches: - - "**" + - "**" + +# Workflow jobs: jobs: - run: - # Don't run Action on forks, and allow skipping CI + + # Define a job for publishing to the gh-pages branch... + publish: + + # Define a display name: + name: 'Publish' + + # Define the type of virtual host machine: + runs-on: ubuntu-latest + + # Avoid running this workflow for forks and allow skipping CI: if: "github.repository == 'data-apis/array-api' && !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip github]')" - runs-on: ubuntu-18.04 + + # Define a sequence of job steps... steps: - # - uses: docker://pandoc/latex:2.9 - - uses: actions/checkout@master - - uses: actions/setup-python@v2 - with: - python-version: '3.10.2' # Version range or exact version of a Python version to use, using semvers version range syntax. - architecture: 'x64' # (x64 or x86) - - run: | - # add dependencies based on the conf.py - pip install -r requirements.txt - - name: Build docs - run: | - # Turn warnings into errors; ensure .doctrees doesn't get deployed - sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - touch build/.nojekyll - - uses: actions/upload-artifact@v2 - if: ${{ github.event_name == 'pull_request'}} - with: - name: html - path: build/ - if-no-files-found: error - - name: Deploy - if: ${{ github.ref == 'refs/heads/main'}} - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./build + + # Checkout the repository: + - name: 'Checkout repository' + uses: actions/checkout@v2 + with: + # Specify whether to remove untracked files before checking out the repository: + clean: false + + # Limit clone depth to the most recent commit: + fetch-depth: 1 + + # Specify whether to download Git-LFS files: + lfs: false + timeout-minutes: 10 + + # Install Python: + - name: 'Install Python' + uses: actions/setup-python@v2 + with: + python-version: '3.10.2' + architecture: 'x64' + + # Install dependencies: + - name: 'Install dependencies' + run: | + pip install -r ./requirements.txt + + # Generate the documentation: + - name: 'Build documentation' + run: | + # Turn warnings into errors; ensure .doctrees doesn't get deployed + sphinx-build -b html -WT --keep-going spec build/latest -d doctrees + touch build/.nojekyll + + # Upload the build artifact: + - name: 'Upload build artifact' + uses: actions/upload-artifact@v2 + if: ${{ github.event_name == 'pull_request'}} + with: + name: html + path: build/ + if-no-files-found: error + + # Deploy the build artifact to gh-pages: + - name: 'Deploy' + uses: peaceiris/actions-gh-pages@v3 + if: ${{ github.ref == 'refs/heads/main'}} + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build From 20a1df394ac72d19e3f28ee8b4a7bbfb2bf704b4 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 04:04:56 -0700 Subject: [PATCH 212/551] Update deployment sequence --- .github/workflows/pages.yml | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 4ea7dca8b..8961889f8 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -65,6 +65,9 @@ jobs: # Specify whether to download Git-LFS files: lfs: false + + # GitHub token: + token: ${{ secrets.GITHUB_TOKEN }} timeout-minutes: 10 # Install Python: @@ -82,9 +85,8 @@ jobs: # Generate the documentation: - name: 'Build documentation' run: | - # Turn warnings into errors; ensure .doctrees doesn't get deployed + # Turn warnings into errors and ensure .doctrees is not deployed: sphinx-build -b html -WT --keep-going spec build/latest -d doctrees - touch build/.nojekyll # Upload the build artifact: - name: 'Upload build artifact' @@ -95,10 +97,27 @@ jobs: path: build/ if-no-files-found: error - # Deploy the build artifact to gh-pages: - - name: 'Deploy' - uses: peaceiris/actions-gh-pages@v3 - if: ${{ github.ref == 'refs/heads/main'}} - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./build + # Configure Git: + - name: 'Configure Git' + run: | + git config --local user.email "noreply@data-apis.org" + git config --local user.name "array-api-bot" + timeout-minutes: 5 + + # Checkout the gh-pages branch: + - name: 'Checkout gh-pages' + run: | + git checkout gh-pages + timeout-minutes: 5 + + # Copy build artifact: + - name: 'Copy build artifact' + run: | + cp -R ./build/latest ./latest + timeout-minutes: 10 + + # Push changes to GitHub: + - name: 'Committing changes' + run: | + git commit -m "Deploy: ${{ github.sha }}" && git push origin gh-pages + timeout-minutes: 10 From cabc301c1b8012818287fec9b7e5dedbcc2e850c Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 04:12:31 -0700 Subject: [PATCH 213/551] Update build sequence --- .github/workflows/pages.yml | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 8961889f8..61b93796c 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -107,6 +107,7 @@ jobs: # Checkout the gh-pages branch: - name: 'Checkout gh-pages' run: | + git fetch --all git checkout gh-pages timeout-minutes: 5 @@ -116,8 +117,14 @@ jobs: cp -R ./build/latest ./latest timeout-minutes: 10 - # Push changes to GitHub: - - name: 'Committing changes' + # Commit changes to: + - name: 'Commit changes' run: | - git commit -m "Deploy: ${{ github.sha }}" && git push origin gh-pages + git add . && git commit -m "Deploy: ${{ github.sha }}" + timeout-minutes: 10 + + # Push changes: + - name: 'Push changes' + run: | + git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/${{ github.repository }}.git" timeout-minutes: 10 From edf2c301196785d8e65b44b12526676b9a994de9 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 2 May 2022 13:25:32 +0200 Subject: [PATCH 214/551] Fix failing preview.yml GitHub Actions job (#422) --- .github/workflows/preview.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index d15d99107..4ca25be0e 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -14,6 +14,3 @@ jobs: artifact-path: 0/build/latest/index.html circleci-jobs: build_page job-title: Check the rendered docs here! - - name: Array API preview - run: | - curl --fail ${{ steps.step1.outputs.url }} | grep $GITHUB_SHA \ No newline at end of file From 7e4cebea2148cd437934b5a687092ea73c55cee8 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 04:39:04 -0700 Subject: [PATCH 215/551] Make push contingent on successful commit --- .github/workflows/pages.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 61b93796c..2c62b47a2 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -121,10 +121,12 @@ jobs: - name: 'Commit changes' run: | git add . && git commit -m "Deploy: ${{ github.sha }}" + continue_on_error: true timeout-minutes: 10 # Push changes: - name: 'Push changes' + if: success() run: | git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/${{ github.repository }}.git" timeout-minutes: 10 From 82027c8ebff50c3e8e5705788fd523396642d5d9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 04:40:37 -0700 Subject: [PATCH 216/551] Fix field name --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 2c62b47a2..8a528bbe5 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -121,7 +121,7 @@ jobs: - name: 'Commit changes' run: | git add . && git commit -m "Deploy: ${{ github.sha }}" - continue_on_error: true + continue-on-error: true timeout-minutes: 10 # Push changes: From dd1aa8760dd6c94a45e2d1fa166f4d8c58c38310 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 04:57:11 -0700 Subject: [PATCH 217/551] Copy to draft directory --- .github/workflows/pages.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 8a528bbe5..1555f8da0 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -86,7 +86,7 @@ jobs: - name: 'Build documentation' run: | # Turn warnings into errors and ensure .doctrees is not deployed: - sphinx-build -b html -WT --keep-going spec build/latest -d doctrees + sphinx-build -b html -WT --keep-going spec build/draft -d doctrees # Upload the build artifact: - name: 'Upload build artifact' @@ -114,7 +114,7 @@ jobs: # Copy build artifact: - name: 'Copy build artifact' run: | - cp -R ./build/latest ./latest + cp -R ./build/draft ./draft timeout-minutes: 10 # Commit changes to: From dbff26a18197954bc54e4008b7a5ec63ea73b61a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 05:04:16 -0700 Subject: [PATCH 218/551] Rename output build directory to `draft` --- .circleci/config.yml | 4 ++-- .github/workflows/preview.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f27e3e5ec..134916b0d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -20,9 +20,9 @@ jobs: no_output_timeout: 25m command: | pip install -r requirements.txt - sphinx-build -b html -WT --keep-going spec build/latest -d doctrees + sphinx-build -b html -WT --keep-going spec build/draft -d doctrees - store_artifacts: - path: build/latest + path: build/draft workflows: version: 2 diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 4ca25be0e..cdfa3c57b 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -11,6 +11,6 @@ jobs: uses: larsoner/circleci-artifacts-redirector-action@master with: repo-token: ${{ secrets.GITHUB_TOKEN }} - artifact-path: 0/build/latest/index.html + artifact-path: 0/build/draft/index.html circleci-jobs: build_page job-title: Check the rendered docs here! From f80d74ae243e27910b32ea86c7e64922cef4a1e7 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 2 May 2022 11:06:25 -0700 Subject: [PATCH 219/551] Remove existing artifact directory --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 1555f8da0..3f22023e4 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -114,7 +114,7 @@ jobs: # Copy build artifact: - name: 'Copy build artifact' run: | - cp -R ./build/draft ./draft + rm -rf ./draft && cp -R ./build/draft ./draft timeout-minutes: 10 # Commit changes to: From 965aac989f831e58c3f6935ed79d19f86f6df588 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Sun, 22 May 2022 16:42:46 -0500 Subject: [PATCH 220/551] Add sphinx extension for rendering TeX equations (#432) --- requirements.txt | 1 + spec/conf.py | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/requirements.txt b/requirements.txt index 4741c6dc8..230413784 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,3 +4,4 @@ myst-parser sphinx_markdown_tables sphinx_copybutton docutils<0.18 +sphinx-math-dollar diff --git a/spec/conf.py b/spec/conf.py index bbb2f5d1d..4813d1420 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -40,6 +40,8 @@ 'sphinx.ext.autosummary', 'sphinx.ext.napoleon', 'sphinx.ext.autodoc', + 'sphinx_math_dollar', + 'sphinx.ext.mathjax' ] autosummary_generate = True @@ -48,6 +50,21 @@ napoleon_custom_sections = [('Returns', 'params_style')] default_role = 'code' +# Mathjax configuration +mathjax_config = { + 'tex2jax': { + 'inlineMath': [ ["\\(","\\)"] ], + 'displayMath': [["\\[","\\]"] ], + }, +} + +mathjax3_config = { + "tex": { + "inlineMath": [['\\(', '\\)']], + "displayMath": [["\\[", "\\]"]], + } +} + # nitpicky = True makes Sphinx warn whenever a cross-reference target can't be # found. nitpicky = True From 73dbcb5657e5f542c3c06f45aa8adfb6b6fe4e3c Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 22 May 2022 14:52:18 -0700 Subject: [PATCH 221/551] Move broadcast functions to list of functions for manipulating arrays (#426) * Move broadcast functions to list of functions for manipulating arrays * Fix list of exports --- .../API_specification/data_type_functions.rst | 2 -- .../manipulation_functions.rst | 2 ++ .../signatures/data_type_functions.py | 36 ++----------------- .../signatures/manipulation_functions.py | 34 +++++++++++++++++- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/spec/API_specification/data_type_functions.rst b/spec/API_specification/data_type_functions.rst index 4b35a297a..136683348 100644 --- a/spec/API_specification/data_type_functions.rst +++ b/spec/API_specification/data_type_functions.rst @@ -19,8 +19,6 @@ Objects in API :template: method.rst astype - broadcast_arrays - broadcast_to can_cast finfo iinfo diff --git a/spec/API_specification/manipulation_functions.rst b/spec/API_specification/manipulation_functions.rst index f2fcbccc5..b290e16e8 100644 --- a/spec/API_specification/manipulation_functions.rst +++ b/spec/API_specification/manipulation_functions.rst @@ -21,6 +21,8 @@ Objects in API :toctree: generated :template: method.rst + broadcast_arrays + broadcast_to concat expand_dims flip diff --git a/spec/API_specification/signatures/data_type_functions.py b/spec/API_specification/signatures/data_type_functions.py index 2356a8b2e..ea9759e92 100644 --- a/spec/API_specification/signatures/data_type_functions.py +++ b/spec/API_specification/signatures/data_type_functions.py @@ -1,4 +1,4 @@ -from ._types import List, Tuple, Union, array, dtype, finfo_object, iinfo_object +from ._types import Union, array, dtype, finfo_object, iinfo_object def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: """ @@ -27,38 +27,6 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: an array having the specified data type. The returned array must have the same shape as ``x``. """ -def broadcast_arrays(*arrays: array) -> List[array]: - """ - Broadcasts one or more arrays against one another. - - Parameters - ---------- - arrays: array - an arbitrary number of to-be broadcasted arrays. - - Returns - ------- - out: List[array] - a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. - """ - -def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: - """ - Broadcasts an array to a specified shape. - - Parameters - ---------- - x: array - array to broadcast. - shape: Tuple[int, ...] - array shape. Must be compatible with ``x`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. - - Returns - ------- - out: array - an array having a specified shape. Must have the same data type as ``x``. - """ - def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: """ Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. @@ -156,4 +124,4 @@ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: the dtype resulting from an operation involving the input arrays and dtypes. """ -__all__ = ['astype', 'broadcast_arrays', 'broadcast_to', 'can_cast', 'finfo', 'iinfo', 'result_type'] +__all__ = ['astype', 'can_cast', 'finfo', 'iinfo', 'result_type'] diff --git a/spec/API_specification/signatures/manipulation_functions.py b/spec/API_specification/signatures/manipulation_functions.py index 64c05db35..9d355f9e5 100644 --- a/spec/API_specification/signatures/manipulation_functions.py +++ b/spec/API_specification/signatures/manipulation_functions.py @@ -1,5 +1,37 @@ from ._types import List, Optional, Tuple, Union, array +def broadcast_arrays(*arrays: array) -> List[array]: + """ + Broadcasts one or more arrays against one another. + + Parameters + ---------- + arrays: array + an arbitrary number of to-be broadcasted arrays. + + Returns + ------- + out: List[array] + a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. + """ + +def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: + """ + Broadcasts an array to a specified shape. + + Parameters + ---------- + x: array + array to broadcast. + shape: Tuple[int, ...] + array shape. Must be compatible with ``x`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + + Returns + ------- + out: array + an array having a specified shape. Must have the same data type as ``x``. + """ + def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0) -> array: """ Joins a sequence of arrays along an existing axis. @@ -146,4 +178,4 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. """ -__all__ = ['concat', 'expand_dims', 'flip', 'permute_dims', 'reshape', 'roll', 'squeeze', 'stack'] \ No newline at end of file +__all__ = [ 'broadcast_arrays', 'broadcast_to', 'concat', 'expand_dims', 'flip', 'permute_dims', 'reshape', 'roll', 'squeeze', 'stack'] \ No newline at end of file From 48c09fcb7ac94906dcb1bdfdefc84a877bac0165 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 22 May 2022 15:42:00 -0700 Subject: [PATCH 222/551] Add complex floating-point data types (#418) * Add complex floating-point data types * Add complex dtypes to numeric category and add real-valued data types category * Replace "numeric data type" with "real-valued data type" This change ensures that the specification maintains the status quo in terms of accepted dtypes for the current set of APIs. Subsequent PRs will add support to APIs for complex number data types on a case-by-case basis. * Add category for real-valued floating-point data types * Fix underline --- spec/API_specification/array_object.rst | 4 +- spec/API_specification/data_types.rst | 44 +++-- .../signatures/array_object.py | 64 +++---- .../signatures/creation_functions.py | 22 +-- .../signatures/data_type_functions.py | 10 +- .../signatures/elementwise_functions.py | 170 +++++++++--------- spec/API_specification/signatures/linalg.py | 72 ++++---- .../signatures/linear_algebra_functions.py | 12 +- .../signatures/searching_functions.py | 4 +- .../signatures/statistical_functions.py | 24 +-- 10 files changed, 221 insertions(+), 205 deletions(-) diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index 55a8ff0ab..f9fa91b1e 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -82,7 +82,7 @@ A conforming implementation of the array API standard must provide and support a - `operator.pow(x1, x2) `_ - `operator.__pow__(x1, x2) `_ -Arithmetic operators should be defined for arrays having numeric data types. +Arithmetic operators should be defined for arrays having real-valued data types. Array Operators ~~~~~~~~~~~~~~~ @@ -94,7 +94,7 @@ A conforming implementation of the array API standard must provide and support a - `operator.matmul(x1, x2) `_ - `operator.__matmul__(x1, x2) `_ -The matmul ``@`` operator should be defined for arrays having numeric data types. +The matmul ``@`` operator should be defined for arrays having real-valued data types. Bitwise Operators ~~~~~~~~~~~~~~~~~ diff --git a/spec/API_specification/data_types.rst b/spec/API_specification/data_types.rst index f40006c4e..f27fdd445 100644 --- a/spec/API_specification/data_types.rst +++ b/spec/API_specification/data_types.rst @@ -62,19 +62,20 @@ float64 IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). -.. note:: - IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. +complex64 +--------- - Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. +Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). -.. admonition:: Future extension - :class: admonition tip +complex128 +---------- - ``complex64`` and ``complex128`` data types are expected to be included in the next version of this standard and to have the following casting rules (will be added to :ref:`type-promotion`): +Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). - .. image:: /_static/images/dtype_promotion_complex.png +.. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. - See `array-api/issues/102 `_ for more details + Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. .. note:: A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. @@ -116,11 +117,14 @@ Default Data Types A conforming implementation of the array API standard must define the following default data types. -- a default floating-point data type (either ``float32`` or ``float64``). +- a default real-valued floating-point data type (either ``float32`` or ``float64``). +- a default complex floating-point data type (either ``complex64`` or ``complex128``). - a default integer data type (either ``int32`` or ``int64``). - a default array index data type (either ``int32`` or ``int64``). -The default floating-point data type must be the same across platforms. +The default real-valued floating-point and complex floating-point data types must be the same across platforms. + +The default complex floating-point point data type should match the default real-valued floating-point data type. For example, if the default real-valued floating-point data type is ``float32``, the default complex floating-point data type must be ``complex64``. If the default real-valued floating-point data type is ``float64``, the default complex floating-point data type must be ``complex128``. The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. @@ -139,14 +143,16 @@ For the purpose of organizing functions within this specification, the following .. note:: Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. -.. note:: - Future versions of the specification will include additional categories for complex data types. - Numeric Data Types ~~~~~~~~~~~~~~~~~~ -``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64`` (i.e., all data types except for ``bool``). +``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. + +Real-valued Data Types +~~~~~~~~~~~~~~~~~~~~~~ + +``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. Integer Data Types ~~~~~~~~~~~~~~~~~~ @@ -156,8 +162,18 @@ Integer Data Types Floating-point Data Types ~~~~~~~~~~~~~~~~~~~~~~~~~ +``float32``, ``float64``, ``complex64``, and ``complex128``. + +Real-valued Floating-point Data Types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ``float32`` and ``float64``. +Complex Floating-point Data Types +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +``complex64`` and ``complex128``. + Boolean Data Types ~~~~~~~~~~~~~~~~~~ diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/signatures/array_object.py index 970f641a1..34a977301 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/signatures/array_object.py @@ -126,7 +126,7 @@ def __abs__(self: array, /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. Returns ------- @@ -170,9 +170,9 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance (augend array). Should have a numeric data type. + array instance (augend array). Should have a real-valued data type. other: Union[int, float, array] - addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -346,7 +346,7 @@ def __float__(self: array, /) -> float: Parameters ---------- self: array - zero-dimensional array instance. Must have a floating-point data type. + zero-dimensional array instance. Must have a real-valued floating-point data type. Returns ------- @@ -400,9 +400,9 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -421,9 +421,9 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -459,9 +459,9 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -532,9 +532,9 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -574,9 +574,9 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -598,9 +598,9 @@ def __matmul__(self: array, other: array, /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + array instance. Should have a real-valued data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. other: array - other array. Should have a numeric data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + other array. Should have a real-valued data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. Returns ------- @@ -665,14 +665,14 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- out: array - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. .. note:: @@ -704,9 +704,9 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -749,7 +749,7 @@ def __neg__(self: array, /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. Returns ------- @@ -789,7 +789,7 @@ def __pos__(self: array, /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. Returns ------- @@ -808,7 +808,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: .. note:: If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + If ``self`` has an integer data type and ``other`` has a real-valued floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. **Special cases** @@ -842,9 +842,9 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + array instance whose elements correspond to the exponentiation base. Should have a real-valued data type. other: Union[int, float, array] - other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -907,9 +907,9 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance (minuend array). Should have a numeric data type. + array instance (minuend array). Should have a real-valued data type. other: Union[int, float, array] - subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -928,7 +928,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: .. note:: If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. **Special cases** @@ -960,14 +960,14 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a numeric data type. + array instance. Should have a real-valued data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- out: array - an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + an array containing the element-wise results. The returned array should have a real-valued floating-point data type determined by :ref:`type-promotion`. .. note:: diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/signatures/creation_functions.py index 88db02340..175cadcc0 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/signatures/creation_functions.py @@ -14,7 +14,7 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None step: Union[int, float] the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default floating-point data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. @@ -47,7 +47,7 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr - if all values are of type ``bool``, the output data type must be ``bool``. - if the values are a mixture of ``bool``\s and ``int``, the output data type must be the default integer data type. - - if one or more values are ``float``\s, the output data type must be the default floating-point data type. + - if one or more values are ``float``\s, the output data type must be the default real-valued floating-point data type. Default: ``None``. @@ -79,7 +79,7 @@ def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, shape: Union[int, Tuple[int, ...]] output array shape. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. @@ -121,7 +121,7 @@ def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Opti k: int index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and ``0`` to the main diagonal. Default: ``0``. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. @@ -162,7 +162,7 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d fill_value: Union[int, float] fill value. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value``. If the fill value is an ``int``, the output array data type must be the default integer data type. If the fill value is a ``float``, the output array data type must be the default floating-point data type. If the fill value is a ``bool``, the output array must have boolean data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value``. If the fill value is an ``int``, the output array data type must be the default integer data type. If the fill value is a ``float``, the output array data type must be the default real-valued floating-point data type. If the fill value is a ``bool``, the output array must have boolean data type. Default: ``None``. .. note:: If the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. @@ -221,7 +221,7 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, num: int number of samples. Must be a non-negative integer value; otherwise, the function must raise an exception. dtype: Optional[dtype] - output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + output array data type. Should be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. endpoint: bool @@ -234,10 +234,10 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, .. note:: - While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + While this specification recommends that this function only return arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. .. note:: - As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output real-valued floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. """ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: @@ -247,7 +247,7 @@ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: Parameters ---------- arrays: array - an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. + an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same real-valued data type. indexing: str Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. @@ -275,7 +275,7 @@ def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, d shape: Union[int, Tuple[int, ...]] output array shape. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. @@ -359,7 +359,7 @@ def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, shape: Union[int, Tuple[int, ...]] output array shape. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be the default floating-point data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. diff --git a/spec/API_specification/signatures/data_type_functions.py b/spec/API_specification/signatures/data_type_functions.py index ea9759e92..44122c1d2 100644 --- a/spec/API_specification/signatures/data_type_functions.py +++ b/spec/API_specification/signatures/data_type_functions.py @@ -8,9 +8,9 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: Casting floating-point ``NaN`` and ``infinity`` values to integral data types is not specified and is implementation-dependent. .. note:: - When casting a boolean input array to a numeric data type, a value of ``True`` must cast to a numeric value equal to ``1``, and a value of ``False`` must cast to a numeric value equal to ``0``. + When casting a boolean input array to a real-valued data type, a value of ``True`` must cast to a numeric value equal to ``1``, and a value of ``False`` must cast to a numeric value equal to ``0``. - When casting a numeric input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. + When casting a real-valued input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. Parameters ---------- @@ -46,17 +46,17 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: def finfo(type: Union[dtype, array], /) -> finfo_object: """ - Machine limits for floating-point data types. + Machine limits for real-valued floating-point data types. Parameters ---------- type: Union[dtype, array] - the kind of floating-point data-type about which to get information. + the kind of real-valued floating-point data-type about which to get information. Returns ------- out: finfo object - an object having the followng attributes: + an object having the following attributes: - **bits**: *int* diff --git a/spec/API_specification/signatures/elementwise_functions.py b/spec/API_specification/signatures/elementwise_functions.py index 213ebe53e..f72af2089 100644 --- a/spec/API_specification/signatures/elementwise_functions.py +++ b/spec/API_specification/signatures/elementwise_functions.py @@ -18,7 +18,7 @@ def abs(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -42,12 +42,12 @@ def acos(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def acosh(x: array, /) -> array: @@ -66,12 +66,12 @@ def acosh(x: array, /) -> array: Parameters ---------- x: array - input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + input array whose elements each represent the area of a hyperbolic sector. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def add(x1: array, x2: array, /) -> array: @@ -106,9 +106,9 @@ def add(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -133,12 +133,12 @@ def asin(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def asinh(x: array, /) -> array: @@ -158,12 +158,12 @@ def asinh(x: array, /) -> array: Parameters ---------- x: array - input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + input array whose elements each represent the area of a hyperbolic sector. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def atan(x: array, /) -> array: @@ -183,12 +183,12 @@ def atan(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def atan2(x1: array, x2: array, /) -> array: @@ -233,14 +233,14 @@ def atan2(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - input array corresponding to the y-coordinates. Should have a floating-point data type. + input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. x2: array - input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a floating-point data type. + input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ @@ -263,12 +263,12 @@ def atanh(x: array, /) -> array: Parameters ---------- x: array - input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + input array whose elements each represent the area of a hyperbolic sector. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def bitwise_and(x1: array, x2: array, /) -> array: @@ -393,7 +393,7 @@ def ceil(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -418,12 +418,12 @@ def cos(x: array, /) -> array: Parameters ---------- x: array - input array whose elements are each expressed in radians. Should have a floating-point data type. + input array whose elements are each expressed in radians. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def cosh(x: array, /) -> array: @@ -443,12 +443,12 @@ def cosh(x: array, /) -> array: Parameters ---------- x: array - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + input array whose elements each represent a hyperbolic angle. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def divide(x1: array, x2: array, /) -> array: @@ -458,7 +458,7 @@ def divide(x1: array, x2: array, /) -> array: .. note:: If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a floating-point data type. + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. **Special cases** @@ -490,14 +490,14 @@ def divide(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - dividend input array. Should have a numeric data type. + dividend input array. Should have a real-valued data type. x2: array - divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- out: array - an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def equal(x1: array, x2: array, /) -> array: @@ -534,12 +534,12 @@ def exp(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def expm1(x: array, /) -> array: @@ -562,12 +562,12 @@ def expm1(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated result for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def floor(x: array, /) -> array: @@ -589,7 +589,7 @@ def floor(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -643,9 +643,9 @@ def floor_divide(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - dividend input array. Should have a numeric data type. + dividend input array. Should have a real-valued data type. x2: array - divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -660,9 +660,9 @@ def greater(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -677,9 +677,9 @@ def greater_equal(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -694,7 +694,7 @@ def isfinite(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -709,7 +709,7 @@ def isinf(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -724,7 +724,7 @@ def isnan(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -739,9 +739,9 @@ def less(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -756,9 +756,9 @@ def less_equal(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -783,12 +783,12 @@ def log(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def log1p(x: array, /) -> array: @@ -812,12 +812,12 @@ def log1p(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated result for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def log2(x: array, /) -> array: @@ -837,12 +837,12 @@ def log2(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def log10(x: array, /) -> array: @@ -862,12 +862,12 @@ def log10(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def logaddexp(x1: array, x2: array, /) -> array: @@ -885,14 +885,14 @@ def logaddexp(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a floating-point data type. + first input array. Should have a real-valued floating-point data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a floating-point data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def logical_and(x1: array, x2: array, /) -> array: @@ -900,7 +900,7 @@ def logical_and(x1: array, x2: array, /) -> array: Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. .. note:: - While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. Parameters ---------- @@ -920,7 +920,7 @@ def logical_not(x: array, /) -> array: Computes the logical NOT for each element ``x_i`` of the input array ``x``. .. note:: - While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. Parameters ---------- @@ -938,7 +938,7 @@ def logical_or(x1: array, x2: array, /) -> array: Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. .. note:: - While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. Parameters ---------- @@ -958,7 +958,7 @@ def logical_xor(x1: array, x2: array, /) -> array: Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. .. note:: - While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having numeric data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. Parameters ---------- @@ -997,9 +997,9 @@ def multiply(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -1017,7 +1017,7 @@ def negative(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -1049,7 +1049,7 @@ def positive(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -1064,7 +1064,7 @@ def pow(x1: array, x2: array, /) -> array: .. note:: If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + If ``x1`` has an integer data type and ``x2`` has a real-valued floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). **Special cases** @@ -1098,9 +1098,9 @@ def pow(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array whose elements correspond to the exponentiation base. Should have a numeric data type. + first input array whose elements correspond to the exponentiation base. Should have a real-valued data type. x2: array - second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -1149,9 +1149,9 @@ def remainder(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - dividend input array. Should have a numeric data type. + dividend input array. Should have a real-valued data type. x2: array - divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -1179,7 +1179,7 @@ def round(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -1200,7 +1200,7 @@ def sign(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -1224,12 +1224,12 @@ def sin(x: array, /) -> array: Parameters ---------- x: array - input array whose elements are each expressed in radians. Should have a floating-point data type. + input array whose elements are each expressed in radians. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def sinh(x: array, /) -> array: @@ -1249,12 +1249,12 @@ def sinh(x: array, /) -> array: Parameters ---------- x: array - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + input array whose elements each represent a hyperbolic angle. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def square(x: array, /) -> array: @@ -1264,7 +1264,7 @@ def square(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- @@ -1289,12 +1289,12 @@ def sqrt(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the square root of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def subtract(x1: array, x2: array, /) -> array: @@ -1304,9 +1304,9 @@ def subtract(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- @@ -1330,12 +1330,12 @@ def tan(x: array, /) -> array: Parameters ---------- x: array - input array whose elements are expressed in radians. Should have a floating-point data type. + input array whose elements are expressed in radians. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def tanh(x: array, /) -> array: @@ -1355,12 +1355,12 @@ def tanh(x: array, /) -> array: Parameters ---------- x: array - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + input array whose elements each represent a hyperbolic angle. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def trunc(x: array, /) -> array: @@ -1382,7 +1382,7 @@ def trunc(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. Returns ------- diff --git a/spec/API_specification/signatures/linalg.py b/spec/API_specification/signatures/linalg.py index 275fa3158..7e838ddf1 100644 --- a/spec/API_specification/signatures/linalg.py +++ b/spec/API_specification/signatures/linalg.py @@ -14,14 +14,14 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square symmetric positive-definite matrices. Should have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square symmetric positive-definite matrices. Should have a real-valued floating-point data type. upper: bool If ``True``, the result must be the upper-triangular Cholesky factor ``U``. If ``False``, the result must be the lower-triangular Cholesky factor ``L``. Default: ``False``. Returns ------- out: array - an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: @@ -31,9 +31,9 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must have the same shape as ``x1``. Should have a numeric data type. + second input array. Must have the same shape as ``x1``. Should have a real-valued data type. axis: int the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. If set to ``-1``, the function computes the cross product for vectors defined by the last axis (dimension). Default: ``-1``. @@ -50,7 +50,7 @@ def det(x: array, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. Returns ------- @@ -97,7 +97,7 @@ def eigh(x: array, /) -> Tuple[array]: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a real-valued floating-point data type. Returns ------- @@ -107,7 +107,7 @@ def eigh(x: array, /) -> Tuple[array]: - first element must have the field name ``eigenvalues`` (corresponding to ``L`` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)``. - second element have have the field name ``eigenvectors`` (corresponding to ``Q`` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)``. - Each returned array must have the same floating-point data type as ``x``. + Each returned array must have the same real-valued floating-point data type as ``x``. .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. @@ -129,7 +129,7 @@ def eigvalsh(x: array, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a real-valued floating-point data type. Returns ------- @@ -147,12 +147,12 @@ def inv(x: array, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + an array containing the multiplicative inverses. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ def matmul(x1: array, x2: array, /) -> array: @@ -167,7 +167,7 @@ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued floating-point data type. keepdims: bool If ``True``, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the last two axes (dimensions) must not be included in the result. Default: ``False``. ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] @@ -210,7 +210,7 @@ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, Returns ------- out: array - an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def matrix_power(x: array, n: int, /) -> array: @@ -220,14 +220,14 @@ def matrix_power(x: array, n: int, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. n: int integer exponent. Returns ------- out: array - if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a real-valued floating-point data type determined by :ref:`type-promotion`. """ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: @@ -237,14 +237,14 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued floating-point data type. rtol: Optional[Union[float, array]] - relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. Returns ------- out: array - an array containing the ranks. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + an array containing the ranks. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). """ def matrix_transpose(x: array, /) -> array: @@ -259,9 +259,9 @@ def outer(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first one-dimensional input array of size ``N``. Should have a numeric data type. + first one-dimensional input array of size ``N``. Should have a real-valued data type. x2: array - second one-dimensional input array of size ``M``. Should have a numeric data type. + second one-dimensional input array of size ``M``. Should have a real-valued data type. Returns ------- @@ -276,14 +276,14 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued floating-point data type. rtol: Optional[Union[float, array]] - relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. Returns ------- out: array - an array containing the pseudo-inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + an array containing the pseudo-inverses. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). """ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tuple[array, array]: @@ -296,7 +296,7 @@ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tupl Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a real-valued floating-point data type. mode: Literal['reduced', 'complete'] decomposition mode. Should be one of the following modes: @@ -313,7 +313,7 @@ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tupl - first element must have the field name ``Q`` and must be an array whose shape depends on the value of ``mode`` and contain matrices with orthonormal columns. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, M)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input array ``x``. - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. - Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + Each returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def slogdet(x: array, /) -> Tuple[array, array]: @@ -326,7 +326,7 @@ def slogdet(x: array, /) -> Tuple[array, array]: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. Returns ------- @@ -338,7 +338,7 @@ def slogdet(x: array, /) -> Tuple[array, array]: For a real matrix, the sign of the determinant must be either ``1``, ``0``, or ``-1``. - Each returned array must have shape ``shape(x)[:-2]`` and a floating-point data type determined by :ref:`type-promotion`. + Each returned array must have shape ``shape(x)[:-2]`` and a real-valued floating-point data type determined by :ref:`type-promotion`. .. note:: If a determinant is zero, then the corresponding ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to ``sign * exp(logsabsdet)`` (although, again, the result may be subject to numerical precision errors). @@ -354,14 +354,14 @@ def solve(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. + coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a real-valued floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: @@ -371,7 +371,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a real-valued floating-point data type. full_matrices: bool If ``True``, compute full-sized ``U`` and ``Vh``, such that ``U`` has shape ``(..., M, M)`` and ``Vh`` has shape ``(..., N, N)``. If ``False``, compute on the leading ``K`` singular vectors, such that ``U`` has shape ``(..., M, K)`` and ``Vh`` has shape ``(..., K, N)`` and where ``K = min(M, N)``. Default: ``True``. @@ -386,7 +386,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. - Each returned array must have the same floating-point data type as ``x``. + Each returned array must have the same real-valued floating-point data type as ``x``. """ def svdvals(x: array, /) -> array: @@ -396,12 +396,12 @@ def svdvals(x: array, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a real-valued floating-point data type. Returns ------- out: array - an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have the same floating-point data type as ``x``. + an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have the same real-valued floating-point data type as ``x``. """ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: @@ -416,7 +416,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a numeric data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued data type. offset: int offset specifying the off-diagonal relative to the main diagonal. @@ -450,7 +450,7 @@ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = No Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. axis: Optional[Union[int, Tuple[int, ...]]] If an integer, ``axis`` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, ``axis`` specifies the axes (dimensions) along which to compute batched vector norms. If ``None``, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: ``None``. keepdims: bool @@ -491,7 +491,7 @@ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = No Returns ------- out: array - an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ __all__ = ['cholesky', 'cross', 'det', 'diagonal', 'eigh', 'eigvalsh', 'inv', 'matmul', 'matrix_norm', 'matrix_power', 'matrix_rank', 'matrix_transpose', 'outer', 'pinv', 'qr', 'slogdet', 'solve', 'svd', 'svdvals', 'tensordot', 'trace', 'vecdot', 'vector_norm'] diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/spec/API_specification/signatures/linear_algebra_functions.py index 30d09c254..275d91856 100644 --- a/spec/API_specification/signatures/linear_algebra_functions.py +++ b/spec/API_specification/signatures/linear_algebra_functions.py @@ -10,9 +10,9 @@ def matmul(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + first input array. Should have a real-valued data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. x2: array - second input array. Should have a numeric data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + second input array. Should have a real-valued data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. Returns ------- @@ -59,9 +59,9 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Should have a numeric data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + second input array. Should have a real-valued data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. .. note:: Contracted axes (dimensions) must not be broadcasted. @@ -90,9 +90,9 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: Parameters ---------- x1: array - first input array. Should have a numeric data type. + first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. axis:int axis over which to compute the dot product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. diff --git a/spec/API_specification/signatures/searching_functions.py b/spec/API_specification/signatures/searching_functions.py index c2875adcc..37da37e24 100644 --- a/spec/API_specification/signatures/searching_functions.py +++ b/spec/API_specification/signatures/searching_functions.py @@ -7,7 +7,7 @@ def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. axis: Optional[int] axis along which to search. If ``None``, the function must return the index of the maximum value of the flattened array. Default: ``None``. keepdims: bool @@ -26,7 +26,7 @@ def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. axis: Optional[int] axis along which to search. If ``None``, the function must return the index of the minimum value of the flattened array. Default: ``None``. keepdims: bool diff --git a/spec/API_specification/signatures/statistical_functions.py b/spec/API_specification/signatures/statistical_functions.py index 4265f28f5..6cdbbb338 100644 --- a/spec/API_specification/signatures/statistical_functions.py +++ b/spec/API_specification/signatures/statistical_functions.py @@ -16,7 +16,7 @@ def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. Default: ``None``. keepdims: bool @@ -42,7 +42,7 @@ def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, kee Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. keepdims: bool @@ -54,7 +54,7 @@ def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, kee if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. .. note:: - While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. """ def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: @@ -73,7 +73,7 @@ def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. Default: ``None``. keepdims: bool @@ -102,14 +102,14 @@ def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dty Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. dtype: Optional[dtype] data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a floating-point data type, the returned array must have the default floating-point data type. + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). @@ -141,7 +141,7 @@ def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which standard deviations must be computed. By default, the standard deviation must be computed over the entire array. If a tuple of integers, standard deviations must be computed over multiple axes. Default: ``None``. correction: Union[int, float] @@ -155,7 +155,7 @@ def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as ``x``. .. note:: - While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. """ def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: @@ -175,14 +175,14 @@ def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtyp Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have a real-valued data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. dtype: Optional[dtype] data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a floating-point data type, the returned array must have the default floating-point data type. + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). @@ -214,7 +214,7 @@ def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which variances must be computed. By default, the variance must be computed over the entire array. If a tuple of integers, variances must be computed over multiple axes. Default: ``None``. correction: Union[int, float] @@ -229,7 +229,7 @@ def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr .. note:: - While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. """ __all__ = ['max', 'mean', 'min', 'prod', 'std', 'sum', 'var'] From fc77b0a003a47b5c6bee95e08ede9448849268d8 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Sun, 22 May 2022 19:03:46 -0500 Subject: [PATCH 223/551] PR: Rename `signatures` module to array_api (#430) * Rename signatures module to array_api * Remove unused code * flatten the namespace in both .rst and .py * Export string name * Rename import and fix list of exports * Remove import * Update import Co-authored-by: Leo Fang Co-authored-by: Athan Reines --- spec/API_specification/array_api/__init__.py | 14 +++++ .../{signatures => array_api}/_types.py | 0 .../{signatures => array_api}/array_object.py | 52 ++++++++++--------- .../{signatures => array_api}/constants.py | 0 .../creation_functions.py | 2 +- .../data_type_functions.py | 0 .../{signatures => array_api}/data_types.py | 2 +- .../elementwise_functions.py | 0 .../{signatures => array_api}/linalg.py | 8 +-- .../linear_algebra_functions.py | 0 .../manipulation_functions.py | 0 .../searching_functions.py | 0 .../set_functions.py | 0 .../sorting_functions.py | 0 .../statistical_functions.py | 0 .../utility_functions.py | 0 spec/API_specification/array_object.rst | 2 +- spec/API_specification/constants.rst | 2 +- spec/API_specification/creation_functions.rst | 2 +- .../API_specification/data_type_functions.rst | 2 +- spec/API_specification/data_types.rst | 2 +- .../elementwise_functions.rst | 2 +- spec/API_specification/indexing.rst | 4 +- .../linear_algebra_functions.rst | 2 +- .../manipulation_functions.rst | 2 +- .../API_specification/searching_functions.rst | 2 +- spec/API_specification/set_functions.rst | 2 +- spec/API_specification/signatures/__init__.py | 0 spec/API_specification/sorting_functions.rst | 2 +- .../statistical_functions.rst | 2 +- spec/API_specification/utility_functions.rst | 2 +- spec/Makefile | 1 + spec/conf.py | 4 +- spec/extensions/linear_algebra_functions.rst | 2 +- 34 files changed, 66 insertions(+), 49 deletions(-) create mode 100644 spec/API_specification/array_api/__init__.py rename spec/API_specification/{signatures => array_api}/_types.py (100%) rename spec/API_specification/{signatures => array_api}/array_object.py (95%) rename spec/API_specification/{signatures => array_api}/constants.py (100%) rename spec/API_specification/{signatures => array_api}/creation_functions.py (99%) rename spec/API_specification/{signatures => array_api}/data_type_functions.py (100%) rename spec/API_specification/{signatures => array_api}/data_types.py (95%) rename spec/API_specification/{signatures => array_api}/elementwise_functions.py (100%) rename spec/API_specification/{signatures => array_api}/linalg.py (99%) rename spec/API_specification/{signatures => array_api}/linear_algebra_functions.py (100%) rename spec/API_specification/{signatures => array_api}/manipulation_functions.py (100%) rename spec/API_specification/{signatures => array_api}/searching_functions.py (100%) rename spec/API_specification/{signatures => array_api}/set_functions.py (100%) rename spec/API_specification/{signatures => array_api}/sorting_functions.py (100%) rename spec/API_specification/{signatures => array_api}/statistical_functions.py (100%) rename spec/API_specification/{signatures => array_api}/utility_functions.py (100%) delete mode 100644 spec/API_specification/signatures/__init__.py diff --git a/spec/API_specification/array_api/__init__.py b/spec/API_specification/array_api/__init__.py new file mode 100644 index 000000000..e5de2e49f --- /dev/null +++ b/spec/API_specification/array_api/__init__.py @@ -0,0 +1,14 @@ +from .array_object import * +from .constants import * +from .creation_functions import * +from .data_type_functions import * +import array_api.data_types as dtype +from .elementwise_functions import * +from .linear_algebra_functions import * +from .manipulation_functions import * +from .searching_functions import * +from .set_functions import * +from .sorting_functions import * +from .statistical_functions import * +from .utility_functions import * +from . import linalg diff --git a/spec/API_specification/signatures/_types.py b/spec/API_specification/array_api/_types.py similarity index 100% rename from spec/API_specification/signatures/_types.py rename to spec/API_specification/array_api/_types.py diff --git a/spec/API_specification/signatures/array_object.py b/spec/API_specification/array_api/array_object.py similarity index 95% rename from spec/API_specification/signatures/array_object.py rename to spec/API_specification/array_api/array_object.py index 34a977301..a8f00bfda 100644 --- a/spec/API_specification/signatures/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -135,7 +135,7 @@ def __abs__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.abs`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -181,7 +181,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.add`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -202,7 +202,7 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_and`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: @@ -239,7 +239,7 @@ def __bool__(self: array, /) -> bool: def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: """ - Exports the array for consumption by :func:`~signatures.creation_functions.from_dlpack` as a DLPack capsule. + Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. Parameters ---------- @@ -294,7 +294,7 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: """ - Returns device type and device ID in DLPack format. Meant for use within :func:`~signatures.creation_functions.from_dlpack`. + Returns device type and device ID in DLPack format. Meant for use within :func:`~array_api.from_dlpack`. Parameters ---------- @@ -336,7 +336,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. """ def __float__(self: array, /) -> float: @@ -411,7 +411,7 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.floor_divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. """ def __ge__(self: array, other: Union[int, float, array], /) -> array: @@ -432,7 +432,7 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. """ def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: @@ -470,7 +470,7 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. """ def __index__(self: array, /) -> int: @@ -522,7 +522,7 @@ def __invert__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_invert`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_invert`. """ def __le__(self: array, other: Union[int, float, array], /) -> array: @@ -543,7 +543,7 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -564,7 +564,7 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_left_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: @@ -585,7 +585,7 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. """ def __matmul__(self: array, other: array, /) -> array: @@ -616,7 +616,7 @@ def __matmul__(self: array, other: array, /) -> array: .. note:: - Results must equal the results returned by the equivalent function :func:`~signatures.linear_algebra_functions.matmul`. + Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. **Raises** @@ -676,7 +676,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.remainder`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ def __mul__(self: array, other: Union[int, float, array], /) -> array: @@ -715,7 +715,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.multiply`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -736,7 +736,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.not_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. """ def __neg__(self: array, /) -> array: @@ -758,7 +758,7 @@ def __neg__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.negative`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -779,7 +779,7 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_or`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -798,7 +798,7 @@ def __pos__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.positive`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: @@ -853,7 +853,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.pow`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -874,7 +874,7 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_right_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: @@ -918,7 +918,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.subtract`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -971,7 +971,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: @@ -992,7 +992,7 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_xor`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: @@ -1019,3 +1019,5 @@ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any """ array = _array + +__all__ = ['array'] diff --git a/spec/API_specification/signatures/constants.py b/spec/API_specification/array_api/constants.py similarity index 100% rename from spec/API_specification/signatures/constants.py rename to spec/API_specification/array_api/constants.py diff --git a/spec/API_specification/signatures/creation_functions.py b/spec/API_specification/array_api/creation_functions.py similarity index 99% rename from spec/API_specification/signatures/creation_functions.py rename to spec/API_specification/array_api/creation_functions.py index 175cadcc0..65244cf97 100644 --- a/spec/API_specification/signatures/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -54,7 +54,7 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr .. admonition:: Note :class: note - If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`signatures.data_type_functions.astype`. + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`array_api.astype`. .. note:: If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. diff --git a/spec/API_specification/signatures/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py similarity index 100% rename from spec/API_specification/signatures/data_type_functions.py rename to spec/API_specification/array_api/data_type_functions.py diff --git a/spec/API_specification/signatures/data_types.py b/spec/API_specification/array_api/data_types.py similarity index 95% rename from spec/API_specification/signatures/data_types.py rename to spec/API_specification/array_api/data_types.py index fd00521f1..a86c9ebe6 100644 --- a/spec/API_specification/signatures/data_types.py +++ b/spec/API_specification/array_api/data_types.py @@ -17,4 +17,4 @@ def __eq__(self: dtype, other: dtype, /) -> bool: a boolean indicating whether the data type objects are equal. """ -all = [__eq__] +__all__ = ['__eq__'] diff --git a/spec/API_specification/signatures/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py similarity index 100% rename from spec/API_specification/signatures/elementwise_functions.py rename to spec/API_specification/array_api/elementwise_functions.py diff --git a/spec/API_specification/signatures/linalg.py b/spec/API_specification/array_api/linalg.py similarity index 99% rename from spec/API_specification/signatures/linalg.py rename to spec/API_specification/array_api/linalg.py index 7e838ddf1..a8b6997b8 100644 --- a/spec/API_specification/signatures/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -157,7 +157,7 @@ def inv(x: array, /) -> array: def matmul(x1: array, x2: array, /) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.matmul`. + Alias for :func:`~array_api.matmul`. """ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: @@ -249,7 +249,7 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a def matrix_transpose(x: array, /) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.matrix_transpose`. + Alias for :func:`~array_api.matrix_transpose`. """ def outer(x1: array, x2: array, /) -> array: @@ -406,7 +406,7 @@ def svdvals(x: array, /) -> array: def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.tensordot`. + Alias for :func:`~array_api.tensordot`. """ def trace(x: array, /, *, offset: int = 0) -> array: @@ -440,7 +440,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.vecdot`. + Alias for :func:`~array_api.vecdot`. """ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py similarity index 100% rename from spec/API_specification/signatures/linear_algebra_functions.py rename to spec/API_specification/array_api/linear_algebra_functions.py diff --git a/spec/API_specification/signatures/manipulation_functions.py b/spec/API_specification/array_api/manipulation_functions.py similarity index 100% rename from spec/API_specification/signatures/manipulation_functions.py rename to spec/API_specification/array_api/manipulation_functions.py diff --git a/spec/API_specification/signatures/searching_functions.py b/spec/API_specification/array_api/searching_functions.py similarity index 100% rename from spec/API_specification/signatures/searching_functions.py rename to spec/API_specification/array_api/searching_functions.py diff --git a/spec/API_specification/signatures/set_functions.py b/spec/API_specification/array_api/set_functions.py similarity index 100% rename from spec/API_specification/signatures/set_functions.py rename to spec/API_specification/array_api/set_functions.py diff --git a/spec/API_specification/signatures/sorting_functions.py b/spec/API_specification/array_api/sorting_functions.py similarity index 100% rename from spec/API_specification/signatures/sorting_functions.py rename to spec/API_specification/array_api/sorting_functions.py diff --git a/spec/API_specification/signatures/statistical_functions.py b/spec/API_specification/array_api/statistical_functions.py similarity index 100% rename from spec/API_specification/signatures/statistical_functions.py rename to spec/API_specification/array_api/statistical_functions.py diff --git a/spec/API_specification/signatures/utility_functions.py b/spec/API_specification/array_api/utility_functions.py similarity index 100% rename from spec/API_specification/signatures/utility_functions.py rename to spec/API_specification/array_api/utility_functions.py diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index f9fa91b1e..758e08582 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -246,7 +246,7 @@ Bitwise Operators ------------------------------------------------- -.. currentmodule:: signatures.array_object +.. currentmodule:: array_api Attributes ---------- diff --git a/spec/API_specification/constants.rst b/spec/API_specification/constants.rst index 4d71ed380..abe256533 100644 --- a/spec/API_specification/constants.rst +++ b/spec/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.constants +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/creation_functions.rst b/spec/API_specification/creation_functions.rst index c34f67378..9984ff04c 100644 --- a/spec/API_specification/creation_functions.rst +++ b/spec/API_specification/creation_functions.rst @@ -11,7 +11,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.creation_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/data_type_functions.rst b/spec/API_specification/data_type_functions.rst index 136683348..d58e438a9 100644 --- a/spec/API_specification/data_type_functions.rst +++ b/spec/API_specification/data_type_functions.rst @@ -9,7 +9,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.data_type_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/data_types.rst b/spec/API_specification/data_types.rst index f27fdd445..2ab926653 100644 --- a/spec/API_specification/data_types.rst +++ b/spec/API_specification/data_types.rst @@ -101,7 +101,7 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: signatures.data_types +.. currentmodule:: array_api.data_types .. autosummary:: :toctree: generated diff --git a/spec/API_specification/elementwise_functions.rst b/spec/API_specification/elementwise_functions.rst index 316ac8ce9..02e3d50b6 100644 --- a/spec/API_specification/elementwise_functions.rst +++ b/spec/API_specification/elementwise_functions.rst @@ -19,7 +19,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.elementwise_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/indexing.rst b/spec/API_specification/indexing.rst index 13fe70a3f..6d5e77a5b 100644 --- a/spec/API_specification/indexing.rst +++ b/spec/API_specification/indexing.rst @@ -154,7 +154,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. .. note:: - Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. - Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. @@ -181,7 +181,7 @@ Boolean Array Indexing An array must support indexing where the **sole index** is an ``M``-dimensional boolean array ``B`` with shape ``S1 = (s1, ..., sM)`` according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S2 = (s1, ..., sM, ..., sN)``. .. note:: - The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~array_api.expand_dims`. - If ``N >= M``, then ``A[B]`` must replace the first ``M`` dimensions of ``A`` with a single dimension having a size equal to the number of ``True`` elements in ``B``. The values in the resulting array must be in row-major (C-style order); this is equivalent to ``A[nonzero(B)]``. diff --git a/spec/API_specification/linear_algebra_functions.rst b/spec/API_specification/linear_algebra_functions.rst index c12144aa4..9bae18e77 100644 --- a/spec/API_specification/linear_algebra_functions.rst +++ b/spec/API_specification/linear_algebra_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t * Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. * Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. -.. currentmodule:: signatures.linear_algebra_functions +.. currentmodule:: array_api Objects in API -------------- diff --git a/spec/API_specification/manipulation_functions.rst b/spec/API_specification/manipulation_functions.rst index b290e16e8..86f708a86 100644 --- a/spec/API_specification/manipulation_functions.rst +++ b/spec/API_specification/manipulation_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.manipulation_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/searching_functions.rst b/spec/API_specification/searching_functions.rst index b8a2b39a5..bf09e4c8a 100644 --- a/spec/API_specification/searching_functions.rst +++ b/spec/API_specification/searching_functions.rst @@ -16,7 +16,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.searching_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/set_functions.rst b/spec/API_specification/set_functions.rst index 4ba2ad424..b7072d100 100644 --- a/spec/API_specification/set_functions.rst +++ b/spec/API_specification/set_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.set_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/signatures/__init__.py b/spec/API_specification/signatures/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/spec/API_specification/sorting_functions.rst b/spec/API_specification/sorting_functions.rst index da0ff99d1..19d7fb439 100644 --- a/spec/API_specification/sorting_functions.rst +++ b/spec/API_specification/sorting_functions.rst @@ -19,7 +19,7 @@ A conforming implementation of the array API standard must provide and support t While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. -.. currentmodule:: signatures.sorting_functions +.. currentmodule:: array_api Objects in API -------------- diff --git a/spec/API_specification/statistical_functions.rst b/spec/API_specification/statistical_functions.rst index d87f5d25a..6734506ed 100644 --- a/spec/API_specification/statistical_functions.rst +++ b/spec/API_specification/statistical_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.statistical_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/API_specification/utility_functions.rst b/spec/API_specification/utility_functions.rst index 887819194..f869b4321 100644 --- a/spec/API_specification/utility_functions.rst +++ b/spec/API_specification/utility_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.utility_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/Makefile b/spec/Makefile index 8082b9728..e71fa39e1 100644 --- a/spec/Makefile +++ b/spec/Makefile @@ -22,3 +22,4 @@ help: clean: -rm -rf $(BUILDDIR) -rm -rf "$(SOURCEDIR)/API_specification/generated" + -rm -rf "$(SOURCEDIR)/extensions/generated" diff --git a/spec/conf.py b/spec/conf.py index 4813d1420..470900803 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -214,9 +214,9 @@ def process_signature(app, what, name, obj, options, signature, return_annotation): if signature: - signature = signature.replace("signatures._types.", "") + signature = signature.replace("array_api._types.", "") if return_annotation: - return_annotation = return_annotation.replace("signatures._types.", "") + return_annotation = return_annotation.replace("array_api._types.", "") return signature, return_annotation def setup(app): diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/extensions/linear_algebra_functions.rst index b82a913de..dbe643bed 100644 --- a/spec/extensions/linear_algebra_functions.rst +++ b/spec/extensions/linear_algebra_functions.rst @@ -74,7 +74,7 @@ Accordingly, the standardization process affords the opportunity to reduce inter where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. -.. currentmodule:: signatures.linalg +.. currentmodule:: array_api.linalg Objects in API -------------- From 34aa9251bec8e53d8e7f4330f0b2b6221b3f6dcb Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 23 May 2022 02:03:39 -0700 Subject: [PATCH 224/551] Update `iinfo` description to be consistent with `finfo` (#439) --- spec/API_specification/array_api/data_type_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py index 44122c1d2..3731e4c98 100644 --- a/spec/API_specification/array_api/data_type_functions.py +++ b/spec/API_specification/array_api/data_type_functions.py @@ -91,7 +91,7 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: Returns ------- out: iinfo object - a class with that encapsules the following attributes: + an object having the following attributes: - **bits**: *int* From 2dd9e6c8f399c0d7150fda75c73179d66a983e07 Mon Sep 17 00:00:00 2001 From: Oleksandr Pavlyk Date: Tue, 24 May 2022 14:58:51 -0500 Subject: [PATCH 225/551] Fix typo (#444) --- spec/design_topics/C_API.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/design_topics/C_API.rst b/spec/design_topics/C_API.rst index ec2b721f8..6a44596b0 100644 --- a/spec/design_topics/C_API.rst +++ b/spec/design_topics/C_API.rst @@ -89,6 +89,6 @@ C API and ABI than CPython offers. A Cython backend targeting HPy will be provid - Universal ABI - single binary for all supported Python versions - Cython backend generating HPy rather than CPython code -HPy isn't quite ready for mainstream usage today, but once it does it may +HPy isn't quite ready for mainstream usage today, but once it is it may help make supporting multiple array libraries or adding non-CPU device support to Cython more feasible. From 5ba86db7ff5f9ddd9e956808c3659b1fc7f714cc Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 29 May 2022 12:42:56 -0700 Subject: [PATCH 226/551] Add complex number support to `meshgrid` (#437) --- spec/API_specification/array_api/creation_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index 65244cf97..eb672b138 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -247,7 +247,7 @@ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: Parameters ---------- arrays: array - an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same real-valued data type. + an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. indexing: str Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. From 7ee81a519d7d6208904bfed3fa5dc890f66911d8 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 11:56:30 -0700 Subject: [PATCH 227/551] Clarify expected behavior when providing a complex number array to `all` and `any` (#442) --- spec/API_specification/array_api/utility_functions.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/API_specification/array_api/utility_functions.py b/spec/API_specification/array_api/utility_functions.py index 79423f455..c05cb948e 100644 --- a/spec/API_specification/array_api/utility_functions.py +++ b/spec/API_specification/array_api/utility_functions.py @@ -7,6 +7,9 @@ def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep .. note:: Positive infinity, negative infinity, and NaN must evaluate to ``True``. + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + .. note:: If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``True``. @@ -32,6 +35,9 @@ def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep .. note:: Positive infinity, negative infinity, and NaN must evaluate to ``True``. + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + .. note:: If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``False``. From 454398d95fa1056a087e82ba95799540dd93ff74 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 11:57:58 -0700 Subject: [PATCH 228/551] Add note concerning complex number output arrays to `eye` (#436) --- spec/API_specification/array_api/creation_functions.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index eb672b138..1832f5b68 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -112,6 +112,9 @@ def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Opti """ Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. + .. note:: + An output array having a complex floating-point data type must have the value ``1 + 0j`` along the ``k``\th diagonal and ``0 + 0j`` elsewhere. + Parameters ---------- n_rows: int From 9a0960aff16a0fabc201572f7e314f5ecd8b422c Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 12:00:44 -0700 Subject: [PATCH 229/551] Clarify expected values in `ones` and `ones_like` when `dtype` is a complex number data type (#438) --- spec/API_specification/array_api/creation_functions.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index 1832f5b68..e5569037f 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -273,6 +273,9 @@ def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, d """ Returns a new array having a specified ``shape`` and filled with ones. + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + Parameters ---------- shape: Union[int, Tuple[int, ...]] @@ -292,6 +295,9 @@ def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[de """ Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + Parameters ---------- x: array From ac7ce5df51441af43c8590156ac0bc8635c614eb Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 12:59:33 -0700 Subject: [PATCH 230/551] Add complex number support to `negative` (#448) --- spec/API_specification/array_api/array_object.py | 5 ++++- spec/API_specification/array_api/elementwise_functions.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index a8f00bfda..34cd3cc7a 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -746,10 +746,13 @@ def __neg__(self: array, /) -> array: .. note:: For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + .. note:: + If ``self`` has a complex floating-point data type, both the real and imaginary components for each ``self_i`` must be negated (a result which follows from the rules of complex number multiplication). + Parameters ---------- self: array - array instance. Should have a real-valued data type. + array instance. Should have a numeric data type. Returns ------- diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index f72af2089..9a6034846 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1014,10 +1014,13 @@ def negative(x: array, /) -> array: .. note:: For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + .. note:: + If ``x`` has a complex floating-point data type, both the real and imaginary components for each ``x_i`` must be negated (a result which follows from the rules of complex number multiplication). + Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- From 3049999db58be3f9a06f50c4e024763977155a21 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 13:00:03 -0700 Subject: [PATCH 231/551] Add complex number support to `positive` (#447) --- spec/API_specification/array_api/array_object.py | 2 +- spec/API_specification/array_api/elementwise_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 34cd3cc7a..bdd335191 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -792,7 +792,7 @@ def __pos__(self: array, /) -> array: Parameters ---------- self: array - array instance. Should have a real-valued data type. + array instance. Should have a numeric data type. Returns ------- diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 9a6034846..7acefaf52 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1052,7 +1052,7 @@ def positive(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- From 660ed015482195fdcbacfad877974a91b6991d5e Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 13:08:23 -0700 Subject: [PATCH 232/551] Add complex number support to `linalg.cholesky` (#443) * Add equations * Fix syntax * Update description and equations * Comment out MathJax config * Remove config due to failing build This config does not seem to be needed. SymPy does not include it in its docs. Seems fine for us to omit, as well, given that it causes builds to fail. * Use raw string * Remove backlash --- spec/API_specification/array_api/linalg.py | 31 ++++++++++++++++------ spec/conf.py | 9 +------ 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index a8b6997b8..483d12632 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -2,26 +2,41 @@ from .constants import inf def cholesky(x: array, /, *, upper: bool = False) -> array: - """ - Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symmetric positive-definite matrix (or a stack of matrices) ``x``, where ``L`` is a lower-triangular matrix or a stack of matrices (``U`` is an upper-triangular matrix or a stack of matrices). + r""" + Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. - .. - NOTE: once complex numbers are supported, each square matrix must be Hermitian. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + + The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = LL^{H} \qquad \text{L $\in\ \mathbb{K}^{n \times n}$} + + where :math:`L` is a lower triangular matrix and :math:`L^{H}` is the conjugate transpose when :math:`L` is complex-valued and the transpose when :math:`L` is real-valued. + + The upper Cholesky decomposition is defined similarly + + .. math:: + x = UU^{H} \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + + where :math:`U` is an upper triangular matrix. + + When ``x`` is a stack of matrices, the function must compute the Cholesky decomposition for each matrix in the stack. .. note:: - Whether an array library explicitly checks whether an input array is a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square symmetric positive-definite matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square complex Hermitian or real symmetric positive-definite matrices. Should have a floating-point data type. upper: bool - If ``True``, the result must be the upper-triangular Cholesky factor ``U``. If ``False``, the result must be the lower-triangular Cholesky factor ``L``. Default: ``False``. + If ``True``, the result must be the upper-triangular Cholesky factor :math:`U`. If ``False``, the result must be the lower-triangular Cholesky factor :math:`L`. Default: ``False``. Returns ------- out: array - an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: diff --git a/spec/conf.py b/spec/conf.py index 470900803..14ccf872b 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -50,14 +50,7 @@ napoleon_custom_sections = [('Returns', 'params_style')] default_role = 'code' -# Mathjax configuration -mathjax_config = { - 'tex2jax': { - 'inlineMath': [ ["\\(","\\)"] ], - 'displayMath': [["\\[","\\]"] ], - }, -} - +# Mathjax configuration: mathjax3_config = { "tex": { "inlineMath": [['\\(', '\\)']], From b09cda65ce73f0322627898dd3064bc00269d363 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 13:11:05 -0700 Subject: [PATCH 233/551] Add complex number support to `asarray` (#434) * Add complex number support to `asarray` * Update copy to include all integer values --- spec/API_specification/array_api/creation_functions.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index e5569037f..b2fa9055d 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -28,13 +28,13 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. """ -def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: +def asarray(obj: Union[array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: """ Convert the input to an array. Parameters ---------- - obj: Union[array, bool, int, float, NestedSequence[bool | int | float], SupportsBufferProtocol] + obj: Union[array, bool, int, float, complex, NestedSequence[bool | int | float | complex], SupportsBufferProtocol] object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. .. admonition:: Tip @@ -43,10 +43,11 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then, in order of precedence, - if all values are of type ``bool``, the output data type must be ``bool``. - - if the values are a mixture of ``bool``\s and ``int``, the output data type must be the default integer data type. + - if all values are of type ``int`` or are a mixture of ``bool`` and ``int``, the output data type must be the default integer data type. + - if one or more values are ``complex`` numbers, the output data type must be the default complex floating-point data type. - if one or more values are ``float``\s, the output data type must be the default real-valued floating-point data type. Default: ``None``. From 41b1b3982e7681780074dc68cd9a1fb95227df72 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jun 2022 13:12:34 -0700 Subject: [PATCH 234/551] Clarify expected behavior when providing a complex number array to `nonzero` (#441) --- spec/API_specification/array_api/searching_functions.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/spec/API_specification/array_api/searching_functions.py b/spec/API_specification/array_api/searching_functions.py index 37da37e24..a76b03f63 100644 --- a/spec/API_specification/array_api/searching_functions.py +++ b/spec/API_specification/array_api/searching_functions.py @@ -42,6 +42,12 @@ def nonzero(x: array, /) -> Tuple[array, ...]: """ Returns the indices of the array elements which are non-zero. + .. note:: + If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + + .. note:: + If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + .. admonition:: Data-dependent output shape :class: admonition important From 6a35bc11d16403ad25d6bf9f0d3ebf87fe25c24b Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 11 Jun 2022 01:08:23 -0700 Subject: [PATCH 235/551] Add complex number support to `full` and `full_like` (#435) * Add complex number support to `full` and `full_like` * Use a list when enumerating rules * Fix missing article * Fix type annotations which omit `bool` --- .../array_api/creation_functions.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index b2fa9055d..17190fe89 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -155,7 +155,7 @@ def from_dlpack(x: object, /) -> array: The returned array may be either a copy or a view. See :ref:`data-interchange` for details. """ -def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: +def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[bool, int, float, complex], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: """ Returns a new array having a specified ``shape`` and filled with ``fill_value``. @@ -163,10 +163,15 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d ---------- shape: Union[int, Tuple[int, ...]] output array shape. - fill_value: Union[int, float] + fill_value: Union[bool, int, float, complex] fill value. dtype: Optional[dtype] - output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value``. If the fill value is an ``int``, the output array data type must be the default integer data type. If the fill value is a ``float``, the output array data type must be the default real-valued floating-point data type. If the fill value is a ``bool``, the output array must have boolean data type. Default: ``None``. + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value`` according to the following rules: + + - If the fill value is an ``int``, the output array data type must be the default integer data type. + - If the fill value is a ``float``, the output array data type must be the default real-valued floating-point data type. + - If the fill value is a ``complex`` number, the output array data type must be the default complex floating-point data type. + - If the fill value is a ``bool``, the output array must have a boolean data type. Default: ``None``. .. note:: If the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. @@ -180,7 +185,7 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d an array where every element is equal to ``fill_value``. """ -def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: +def full_like(x: array, /, fill_value: Union[bool, int, float, complex], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: """ Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. @@ -188,7 +193,7 @@ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dty ---------- x: array input array from which to derive the output array shape. - fill_value: Union[int, float] + fill_value: Union[bool, int, float, complex] fill value. dtype: Optional[dtype] output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. @@ -197,7 +202,7 @@ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dty If the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. .. note:: - If the ``fill_value`` has a data type (``int`` or ``float``) which is not of the same data type kind as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + If the ``fill_value`` has a data type which is not of the same data type kind (boolean, integer, or floating-point) as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. device: Optional[device] device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. From 42eb7a0cb90d5e5c742a64be74d0a8d6b17b3fa8 Mon Sep 17 00:00:00 2001 From: Kenichi Maehashi <939877+kmaehashi@users.noreply.github.com> Date: Mon, 20 Jun 2022 11:56:46 +0900 Subject: [PATCH 236/551] Use raw string for docstrings containing escape sequences (#455) --- spec/API_specification/array_api/creation_functions.py | 2 +- spec/API_specification/array_api/elementwise_functions.py | 2 +- spec/API_specification/array_api/linalg.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index 17190fe89..830337905 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -29,7 +29,7 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None """ def asarray(obj: Union[array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: - """ + r""" Convert the input to an array. Parameters diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 7acefaf52..e75b087c9 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -598,7 +598,7 @@ def floor(x: array, /) -> array: """ def floor_divide(x1: array, x2: array, /) -> array: - """ + r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. .. note:: diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 483d12632..abce23437 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -459,7 +459,7 @@ def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: - """ + r""" Computes the vector norm of a vector (or batch of vectors) ``x``. Parameters From 596ef9418bc0800455291c97110b7d30444795a3 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 7 Jul 2022 02:41:34 -0700 Subject: [PATCH 237/551] Add complex number support to `round` (#440) * Add complex number support to `round`, `ceil`, `floor`, and `trunc` * Remove complex dtype support for `floor`, `ceil`, and `trunc` --- .../array_api/elementwise_functions.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index e75b087c9..02dc1ace2 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1166,8 +1166,16 @@ def round(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. + .. note:: + For complex floating-point operands, real and imaginary components must be independently rounded to the nearest integer-valued number. + + Rounded real and imaginary components must be equal to their equivalent rounded real-valued floating-point counterparts (i.e., for complex-valued ``x``, ``real(round(x))`` must equal ``round(real(x)))`` and ``imag(round(x))`` must equal ``round(imag(x))``). + **Special cases** + .. note:: + For complex floating-point operands, the following special cases apply to real and imaginary components independently (e.g., if ``real(x_i)`` is ``NaN``, the rounded real component is ``NaN``). + - If ``x_i`` is already integer-valued, the result is ``x_i``. For floating-point operands, @@ -1182,7 +1190,7 @@ def round(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- From 19b830de6474d6221f4d915f311b18a0113ca137 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 7 Jul 2022 02:45:09 -0700 Subject: [PATCH 238/551] Add complex number support to `exp` (#451) * Update ignore file * Add complex number support to `exp` * Update input and output data types * Update description to accommodate complex number input * Add note concerning complex conjugation * Specify special case in terms of `cis` function * Fix special cases and move note * Fix `cis` argument --- .gitignore | 1 + .../array_api/elementwise_functions.py | 36 +++++++++++++++---- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 73e203a64..86bab2717 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,4 @@ node_modules/ __pycache__/ *.pyc spec/**/generated +tmp/ \ No newline at end of file diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 02dc1ace2..319151a41 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -223,8 +223,8 @@ def atan2(x1: array, x2: array, /) -> array: - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+π``. - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``-0``. - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is finite, the result is an implementation-dependent approximation to ``+π/2``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is finite, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``-π/2``. - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/4``. - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. @@ -519,11 +519,11 @@ def equal(x1: array, x2: array, /) -> array: def exp(x: array, /) -> array: """ - Calculates an implementation-dependent approximation to the exponential function, having domain ``[-infinity, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``1``. @@ -531,15 +531,39 @@ def exp(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - If ``x_i`` is ``-infinity``, the result is ``+0``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def expm1(x: array, /) -> array: From b43dcb1c59989e643dcaccecd7587268881a5000 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 7 Jul 2022 02:46:43 -0700 Subject: [PATCH 239/551] Add complex number support to `cosh` (#453) * Add complex number support to `cosh` * Add missing comma * Move notes and fix special cases --- .../array_api/elementwise_functions.py | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 319151a41..70bcc6574 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -427,12 +427,20 @@ def cos(x: array, /) -> array: """ def cosh(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the hyperbolic cosine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the hyperbolic cosine for each element ``x_i`` in the input array ``x``. + + The mathematical definition of the hyperbolic cosine is + + .. math:: + \operatorname{cosh}(x) = \frac{e^x + e^{-x}}{2} **Special cases** - For floating-point operands, + .. note:: + For all operands, ``cosh(x)`` must equal ``cosh(-x)``. + + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``1``. @@ -440,15 +448,38 @@ def cosh(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``cosh(conj(x))`` must equal ``conj(cosh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is either ``+0`` or ``-0``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. note:: + The hyperbolic cosine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + Parameters ---------- x: array - input array whose elements each represent a hyperbolic angle. Should have a real-valued floating-point data type. + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. Returns ------- out: array - an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def divide(x1: array, x2: array, /) -> array: From e3fdf17440262d87143fbbc956837ad1defe7733 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 7 Jul 2022 02:48:13 -0700 Subject: [PATCH 240/551] Add complex number support to `cos` (#454) * Add complex number support to `cos` * Fix equation * Fix equation variable * Fix variable name --- .../array_api/elementwise_functions.py | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 70bcc6574..8512f246e 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -402,12 +402,14 @@ def ceil(x: array, /) -> array: """ def cos(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the cosine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. + r""" + Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``1``. @@ -415,15 +417,28 @@ def cos(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``NaN``. - If ``x_i`` is ``-infinity``, the result is ``NaN``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. note:: + The cosine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of cosine is + + .. math:: + \begin{align} \operatorname{cos}(x) &= \sum_{n=0}^\infty \frac{(-1)^n}{(2n)!} x^{2n} \\ &= \frac{e^{jx} + e^{-jx}}{2} \\ &= \operatorname{cosh}(jx) \end{align} + + where :math:`\operatorname{cosh}` is the hyperbolic cosine. + Parameters ---------- x: array - input array whose elements are each expressed in radians. Should have a real-valued floating-point data type. + input array whose elements are each expressed in radians. Should have a floating-point data type. Returns ------- out: array - an array containing the cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def cosh(x: array, /) -> array: From 39911e8ce602a6f96a3b4da1eeef14823a386149 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 7 Jul 2022 02:49:20 -0700 Subject: [PATCH 241/551] Add complex number support to `sinh` (#456) * Add complex number support to `sinh` * Fix zeros handling in special cases * Move notes --- .../array_api/elementwise_functions.py | 41 ++++++++++++++++--- 1 file changed, 36 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 8512f246e..c6be553f6 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1314,12 +1314,20 @@ def sin(x: array, /) -> array: """ def sinh(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the hyperbolic sine for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic sine is + + .. math:: + \operatorname{sinh}(x) = \frac{e^x - e^{-x}}{2} **Special cases** - For floating-point operands, + .. note:: + For all operands, ``sinh(x)`` must equal ``-sinh(-x)``. + + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. @@ -1327,15 +1335,38 @@ def sinh(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``sinh(conj(x))`` must equal ``conj(sinh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. note:: + The hyperbolic sine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + Parameters ---------- x: array - input array whose elements each represent a hyperbolic angle. Should have a real-valued floating-point data type. + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. Returns ------- out: array - an array containing the hyperbolic sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def square(x: array, /) -> array: From 3c7395c8b681762454f154b7556d75a0fb60676e Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 7 Jul 2022 02:50:18 -0700 Subject: [PATCH 242/551] Add complex number support to `sin` (#457) * Add complex number support to `sin` * Update equation --- .../array_api/elementwise_functions.py | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index c6be553f6..ed422cc08 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1290,27 +1290,42 @@ def sign(x: array, /) -> array: """ def sin(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the sine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. + r""" + Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. note:: + The sine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of sine is + + .. math:: + \begin{align} \operatorname{sin}(x) &= \frac{e^{jx} - e^{-jx}}{2j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \cdot \frac{j}{j} \\ &= -j \cdot \operatorname{sinh}(jx) \end{align} + + where :math:`\operatorname{sinh}` is the hyperbolic sine. + Parameters ---------- x: array - input array whose elements are each expressed in radians. Should have a real-valued floating-point data type. + input array whose elements are each expressed in radians. Should have a floating-point data type. Returns ------- out: array - an array containing the sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def sinh(x: array, /) -> array: From bc495887bbae912d5486dba7afb6229c7ae00116 Mon Sep 17 00:00:00 2001 From: IsaacBreen <57783927+IsaacBreen@users.noreply.github.com> Date: Wed, 27 Jul 2022 22:59:59 +0800 Subject: [PATCH 243/551] Add `self` param to array object properties (#464) --- spec/API_specification/array_api/array_object.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index bdd335191..94dac2d1d 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -4,13 +4,13 @@ Union, Any, PyCapsule, Enum, ellipsis) class _array(): - def __init__(self) -> None: + def __init__(self: array) -> None: """ Initialize the attributes for the array object class. """ @property - def dtype() -> Dtype: + def dtype(self: array) -> Dtype: """ Data type of the array elements. @@ -21,7 +21,7 @@ def dtype() -> Dtype: """ @property - def device() -> Device: + def device(self: array) -> Device: """ Hardware device the array data resides on. @@ -32,7 +32,7 @@ def device() -> Device: """ @property - def mT() -> array: + def mT(self: array) -> array: """ Transpose of a matrix (or a stack of matrices). @@ -45,7 +45,7 @@ def mT() -> array: """ @property - def ndim() -> int: + def ndim(self: array) -> int: """ Number of array dimensions (axes). @@ -56,7 +56,7 @@ def ndim() -> int: """ @property - def shape() -> Tuple[Optional[int], ...]: + def shape(self: array) -> Tuple[Optional[int], ...]: """ Array dimensions. @@ -74,7 +74,7 @@ def shape() -> Tuple[Optional[int], ...]: """ @property - def size() -> Optional[int]: + def size(self: array) -> Optional[int]: """ Number of elements in an array. @@ -92,7 +92,7 @@ def size() -> Optional[int]: """ @property - def T() -> array: + def T(self: array) -> array: """ Transpose of the array. From 92bbafb4b49f29c1717df1f304be335dd453190b Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 28 Jul 2022 17:28:34 -0500 Subject: [PATCH 244/551] Indicate dtypes for inputs and expected outputs --- .../array_api/fourier_transform_functions.py | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 7bf8ba701..6bdd41767 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -8,7 +8,7 @@ def fft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'ba Parameters ---------- a: array - input array + input array. Should have a floating-point data type. n: int length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length ``n`` before computing the Fourier transform. Otherwise, the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. axis: int @@ -25,7 +25,7 @@ def fft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'ba Returns ------- out: array - a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. + a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -41,7 +41,7 @@ def ifft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'b Parameters ---------- a: array - input array + input array. Should have a floating-point data type. n: int length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length ``n`` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. axis: int @@ -58,7 +58,7 @@ def ifft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'b Returns ------- out: array - a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. + a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -74,7 +74,7 @@ def fftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Parameters ---------- a: array - input array + input array. Should have a floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] size of each transformed axis of the output. If given, each axis ``i`` will be either zero-padded or trimmed to the length ``s[i]`` before computing the Fourier transform. Otherwise, the shape of the input along the axes given by the ``axes`` keyword. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] @@ -91,7 +91,7 @@ def fftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Returns ------- out: array - an array transformed along the axes indicated by the ``axes`` keyword. + an array transformed along the axes indicated by the ``axes`` keyword. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -108,7 +108,7 @@ def ifftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Parameters ---------- a: array - input array + input array. Should have a floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length ``s[i]`` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the ``axes`` keyword. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] @@ -125,7 +125,7 @@ def ifftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Returns ------- out: array - an array transformed along the axes indicated by the `axes` keyword. + an array transformed along the axes indicated by the `axes` keyword. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -142,7 +142,7 @@ def rfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'b Parameters ---------- a: array - input array + input array. Should have a floating-point data type. n: int length of the transformed axis of the **input**. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the ``axis`` keyword is used. Default: ``None``. axis: int @@ -159,7 +159,7 @@ def rfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'b Returns ------- out: array - a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. + a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -175,7 +175,7 @@ def irfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = ' Parameters ---------- a: array - input array + input array. Should have a floating-point data type. n: int length of the transformed axis of the **output**. If given, the input will be either zero-padded or trimmed to ``n//2+1`` before computing the inverse of ``rfft``. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. axis: int @@ -192,7 +192,7 @@ def irfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = ' Returns ------- out: array - a real-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n`` (if given) or ``2 * (m - 1)``. + a real-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n`` (if given) or ``2 * (m - 1)``. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -208,7 +208,7 @@ def rfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Parameters ---------- a: array - input array + input array. Should have a floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] size of each transformed axis of the output. If given, each axis ``i`` will be either zero-padded or trimmed to the length ``s[i]`` before computing the real Fourier transform. Otherwise, the shape of the input along the axes given by the `axes` keyword. The last element ``s[-1]`` is for computing ``rfft(a[axes[-1]], n=s[-1])`` whereas other elements for ``fft(a[axes[i]], n=s[i])``. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] @@ -225,7 +225,7 @@ def rfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Returns ------- out: array - a complex-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]//2+1`` and along other axes ``s[i]``. + a complex-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]//2+1`` and along other axes ``s[i]``. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -242,7 +242,7 @@ def irfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes Parameters ---------- a: array - input array + input array. Should have a floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] size of each transformed axis of the **output**. If given, the last axis will be either zero-padded or trimmed to ``s[-1]//2+1``, whereas all other axes ``i`` are either zero-padded or trimmed to the length ``s[i]``, before computing the inverse of ``rfftn``. Otherwise, the last axis is either zero-padded or trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis, and all other axes use the input shape. The last element ``s[-1]`` is for computing ``irfft(a[axes[-1]], n=s[-1])`` whereas other elements for ``ifft(a[axes[i]], n=s[i])``. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] @@ -259,7 +259,7 @@ def irfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes Returns ------- out: array - a real-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. + a real-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -276,7 +276,7 @@ def hfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'b Parameters ---------- a: array - input array + input array. Should have a floating-point data type. n: int length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. axis: int @@ -293,7 +293,7 @@ def hfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'b Returns ------- out: array - a transformed array. + a transformed array. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -309,7 +309,7 @@ def ihfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = ' Parameters ---------- a: array - input array + input array. Should have a floating-point data type. n: int length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. axis: int @@ -326,7 +326,7 @@ def ihfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = ' Returns ------- out: array - a transformed array. + a transformed array. The returned array must have a complex dtype with the same precision as the input ``x``. **Raises** @@ -392,7 +392,7 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int], Tuple[int, ...]] = Parameters ---------- x: array - input array. + input array. Should have a floating-point data type. axes: Union[int, Sequence[int], Tuple[int, ...]] axes over which to shift. If not specified, it shifts all axes. Default: ``None``. @@ -410,7 +410,7 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int], Tuple[int, ...]] = Parameters ---------- x: array - input array. + input array. Should have a floating-point data type. axes: Union[int, Sequence[int], Tuple[int, ...]] axes over which to calculate. If not specified, it shifts all axes. Default: ``None``. From 07730170ca2bb6264282cf897e1088108d94188a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Thu, 28 Jul 2022 17:35:52 -0500 Subject: [PATCH 245/551] Fix current module name --- spec/extensions/fourier_transform_functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/extensions/fourier_transform_functions.rst b/spec/extensions/fourier_transform_functions.rst index 4859c7d0c..d6be0634d 100644 --- a/spec/extensions/fourier_transform_functions.rst +++ b/spec/extensions/fourier_transform_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.fourier_transform_functions +.. currentmodule:: array_api.fourier_transform_functions .. NOTE: please keep the functions and their inverse together From 0ddf4f9ba21427a2cd0d77ae6f2b9dae5f5d14ba Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 29 Jul 2022 11:22:58 +0200 Subject: [PATCH 246/551] CI: fix broken gh-pages CI job, should only run on commits in main (#467) Also I enabled CircleCI preview builds on PRs from forks, it was missing a setting in the CircleCI UI Closes gh-466 --- .github/workflows/pages.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 3f22023e4..ffebdf3c2 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -31,10 +31,6 @@ on: branches: - main - pull_request: - branches: - - "**" - # Workflow jobs: jobs: From 792f11e86405ef30281ad2ae32295766ae53278b Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 29 Jul 2022 12:16:22 +0200 Subject: [PATCH 247/551] CI: fix deploy to gh-pages branch The `GITHUB_SECRETS` usage was causing a permissions issue, and it seems no longer necessary. --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index ffebdf3c2..8709257c1 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -124,5 +124,5 @@ jobs: - name: 'Push changes' if: success() run: | - git push "https://$GITHUB_ACTOR:$GITHUB_TOKEN@github.com/${{ github.repository }}.git" + git push origin gh-pages timeout-minutes: 10 From ac64f2ec4ccdff2cc985879e12a78bbfd782e7e2 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 1 Aug 2022 15:05:02 -0500 Subject: [PATCH 248/551] Add review comments --- .../array_api/fourier_transform_functions.py | 344 +++++++++--------- 1 file changed, 181 insertions(+), 163 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 6bdd41767..94ba48fd0 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -1,337 +1,355 @@ -from ._types import Tuple, Union, Sequence, array, Optional +from ._types import Tuple, Union, Sequence, array, Optional, Literal - -def fft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: +def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ - Computes the one-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifft(fft(a)) == a`` within numerical accuracy. + Computes the one-dimensional discrete Fourier transform. + + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``ifft(fft(x)) == x``. Parameters ---------- - a: array + x: array input array. Should have a floating-point data type. n: int - length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length ``n`` before computing the Fourier transform. Otherwise, the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + length of the transformed axis of the output. If + + - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + + if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int - axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. - norm: str - specify the normalization mode. Should be one of the following modes: + axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: No normalization. - - ``'ortho'``: Normalize by ``1/sqrt(n)``. - - ``'forward'``: Normalize by ``1/n``. + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'forward'``: normalize by ``1/n``. Default: ``'backward'``. Returns ------- out: array - a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. The returned array must have a complex dtype with the same precision as the input ``x``. - - - **Raises** - - - If ``axis`` is not a valid axis of ``a``. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. """ -def ifft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: +def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ - Computes the one-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifft(fft(a)) == a`` within numerical accuracy. + Computes the one-dimensional inverse discrete Fourier transform. Parameters ---------- - a: array + x: array input array. Should have a floating-point data type. n: int - length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to the length ``n`` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + length of the transformed axis of the output. If + + - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + + if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int - axis used to compute the inverse Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. - norm: str - specify the normalization mode. Should be one of the following modes: + axis (dimension) over which to compute the inverse Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: Normalize by ``1/n``. - - ``'ortho'``: Normalize by ``1/sqrt(n)`` - - ``'forward'``: No normalization. + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'forward'``: no normalization. Default: ``'backward'``. Returns ------- out: array - a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. The returned array must have a complex dtype with the same precision as the input ``x``. - + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + """ - **Raises** - - If ``axis`` is not a valid axis of ``a``. +def fftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ + Computes the n-dimensional discrete Fourier transform. -def fftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: - """ - Computes the n-dimensional discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifftn(fftn(a)) == a`` within numerical accuracy. + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``ifftn(fftn(x)) == x``. Parameters ---------- - a: array + x: array input array. Should have a floating-point data type. + n: int + length of the transformed axis of the output. If + + - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + + if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. s: Union[Sequence[int], Tuple[int, ...]] - size of each transformed axis of the output. If given, each axis ``i`` will be either zero-padded or trimmed to the length ``s[i]`` before computing the Fourier transform. Otherwise, the shape of the input along the axes given by the ``axes`` keyword. Default: ``None``. + size of each transformed axis of the output. If + + - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. + - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + + if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] - axes over which to compute the Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. - norm: str - specify the normalization mode. Should be one of the following modes: + axes (dimension) over which to compute the Fourier transform. If set to ``None``, the last ``len(s)`` axes are used, or all axes if ``s`` is set to ``-1``. Default: ``None``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: No normalization. - - ``'ortho'``: Normalize by ``1/sqrt(n)``. - - ``'forward'``: Normalize by ``1/n``. + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'forward'``: normalize by ``1/n``. Default: ``'backward'``. Returns ------- out: array - an array transformed along the axes indicated by the ``axes`` keyword. The returned array must have a complex dtype with the same precision as the input ``x``. - - - **Raises** - - - If ``s`` and ``axes`` have different lengths. - - If ``axes`` contains any invalid axis of ``a``. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determine by :ref:`type-promotion`. """ -def ifftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: +def ifftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ - Computes the n-dimensional inverse discrete Fourier transform. The expected behavior includes a round-trip transform using the inverse function, ``ifftn(fftn(a)) == a`` within numerical accuracy. + Computes the n-dimensional inverse discrete Fourier transform. Parameters ---------- - a: array + x: array input array. Should have a floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] - size of each transformed axis of the output. If given, each axis will be either zero-padded or trimmed to the length ``s[i]`` before computing the inverse Fourier transform. Otherwise, the length of the input along the axis given by the ``axes`` keyword. Default: ``None``. + size of each transformed axis of the output. If + + - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. + - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + + if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] axes over which to compute the inverse Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. - norm: str + norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: - - ``'backward'``: Normalize by ``1/n``. - - ``'ortho'``: Normalize by ``1/sqrt(n)`` - - ``'forward'``: No normalization. + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'forward'``: no normalization. Default: ``'backward'``. Returns ------- out: array - an array transformed along the axes indicated by the `axes` keyword. The returned array must have a complex dtype with the same precision as the input ``x``. - + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determine by :ref:`type-promotion`. + """ - **Raises** - - If ``s`` and ``axes`` have different lengths. - - If ``axes`` contains any invalid axis of ``a``. +def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ + Computes the one-dimensional discrete Fourier transform for real-valued input. -def rfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: - """ - Computes the one-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, ``irfft(rfft(a), n=a.shape[axis]) == a`` within numerical accuracy. + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``irfft(rfft(x), n=x.shape[axis]) == x``. Parameters ---------- - a: array - input array. Should have a floating-point data type. + x: array + input array. Should have a real-valued floating-point data type. n: int - length of the transformed axis of the **input**. If given, the input will be either zero-padded or trimmed to this length before computing the real Fourier transform. Otherwise, the length of the input along the axis specified by the ``axis`` keyword is used. Default: ``None``. + length of the transformed axis of the **input**. If + + - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + + if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int - axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. - norm: str - specify the normalization mode. Should be one of the following modes: + axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: No normalization. - - ``'ortho'``: Normalize by ``1/sqrt(n)``. - - ``'forward'``: Normalize by ``1/n``. + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'forward'``: normalize by ``1/n``. Default: ``'backward'``. Returns ------- out: array - a complex-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n//2+1``. The returned array must have a complex dtype with the same precision as the input ``x``. - - - **Raises** - - - If ``axis`` is not a valid axis of ``a``. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. """ -def irfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: +def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ - Computes the one-dimensional inverse of ``rfft``. The expected behavior includes a round-trip transform using the inverse function, ``irfft(rfft(a), n=a.shape[axis]) == a`` within numerical accuracy. + Computes the one-dimensional inverse of ``rfft``. Parameters ---------- - a: array - input array. Should have a floating-point data type. + x: array + input array. Should have a real-valued floating-point data type. n: int - length of the transformed axis of the **output**. If given, the input will be either zero-padded or trimmed to ``n//2+1`` before computing the inverse of ``rfft``. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + length of the transformed axis of the **output**. If + + - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n//2+1``. + + if not provided, the length of the transformed axis of the output must equal the length ``2 * (m - 1)`` where ``m`` is the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int - axis used to compute the real Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. - norm: str - specify the normalization mode. Should be one of the following modes: + axis (dimension) over which to compute the inverse Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: Normalize by ``1/n``. - - ``'ortho'``: Normalize by ``1/sqrt(n)`` - - ``'forward'``: No normalization. + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'forward'``: no normalization. Default: ``'backward'``. Returns ------- out: array - a real-valued array transformed along the axis indicated by the ``axis`` keyword. The length along the transformed axis is ``n`` (if given) or ``2 * (m - 1)``. The returned array must have a complex dtype with the same precision as the input ``x``. - + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2 * (m - 1)``. + """ - **Raises** - - If ``axis`` is not a valid axis of ``a``. +def rfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ + Computes the n-dimensional discrete Fourier transform for real-valued input. -def rfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: - """ - Computes the n-dimensional discrete Fourier transform for real-valued input. The expected behavior includes a round-trip transform using the inverse function, ``irfftn(rfftn(a), s=a.shape) == a`` within numerical accuracy. + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``irfftn(rfftn(x), n=x.shape[axis]) == x``. Parameters ---------- - a: array - input array. Should have a floating-point data type. + x: array + input array. Should have a real-valued floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] - size of each transformed axis of the output. If given, each axis ``i`` will be either zero-padded or trimmed to the length ``s[i]`` before computing the real Fourier transform. Otherwise, the shape of the input along the axes given by the `axes` keyword. The last element ``s[-1]`` is for computing ``rfft(a[axes[-1]], n=s[-1])`` whereas other elements for ``fft(a[axes[i]], n=s[i])``. Default: ``None``. + size of each transformed axis of the output. If + + - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. + - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + + if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] axes over which to compute the Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. - norm: str - specify the normalization mode. Should be one of the following modes: + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: No normalization. - - ``'ortho'``: Normalize by ``1/sqrt(n)``. - - ``'forward'``: Normalize by ``1/n``. + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'forward'``: normalize by ``1/n``. Default: ``'backward'``. Returns ------- out: array - a complex-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]//2+1`` and along other axes ``s[i]``. The returned array must have a complex dtype with the same precision as the input ``x``. - - - **Raises** - - - If ``s`` and ``axes`` have different lengths. - - If ``axes`` contains any invalid axis of ``a``. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. """ -def irfftn(a: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: str = 'backward') -> array: +def irfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ - Computes the n-dimensional inverse of ``rfftn``. The expected behavior includes a round-trip transform using the inverse function, ``irfftn(rfftn(a), s=a.shape) == a`` within numerical accuracy. + Computes the n-dimensional inverse of ``rfftn``. Parameters ---------- - a: array - input array. Should have a floating-point data type. + x: array + input array. Should have a real-valued floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] - size of each transformed axis of the **output**. If given, the last axis will be either zero-padded or trimmed to ``s[-1]//2+1``, whereas all other axes ``i`` are either zero-padded or trimmed to the length ``s[i]``, before computing the inverse of ``rfftn``. Otherwise, the last axis is either zero-padded or trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis, and all other axes use the input shape. The last element ``s[-1]`` is for computing ``irfft(a[axes[-1]], n=s[-1])`` whereas other elements for ``ifft(a[axes[i]], n=s[i])``. Default: ``None``. + size of each transformed axis of the **output**. If + + - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. + - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. Except for the last axis is trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis. + + if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. axes: Union[Sequence[int], Tuple[int, ...]] - axes over which to compute the inverse Fourier transform. If it is not specified, the last ``len(s)`` axes are used or all axes if ``s`` is also not specified. Default: ``None``. - norm: str - specify the normalization mode. Should be one of the following modes: + axes over which to compute the inverse Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: Normalize by ``1/n``. - - ``'ortho'``: Normalize by ``1/sqrt(n)`` - - ``'forward'``: No normalization. + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'forward'``: no normalization. Default: ``'backward'``. Returns ------- out: array - a real-valued array transformed along the axes indicated by the ``axes`` keyword. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. The returned array must have a complex dtype with the same precision as the input ``x``. - - - **Raises** - - - If ``s`` and ``axes`` have different lengths. - - If ``axes`` contains any invalid axis of ``a``. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. """ -def hfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: +def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. Parameters ---------- - a: array - input array. Should have a floating-point data type. + x: array + input array. Should have a complex floating-point data type. n: int - length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + length of the transformed axis of the output. If + + - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + + if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int - axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. - norm: str - specify the normalization mode. Should be one of the following modes: + axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: No normalization. - - ``'ortho'``: Normalize by ``1/sqrt(n)``. - - ``'forward'``: Normalize by ``1/n``. + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'forward'``: normalize by ``1/n``. Default: ``'backward'``. Returns ------- out: array - a transformed array. The returned array must have a complex dtype with the same precision as the input ``x``. - - - **Raises** - - - If ``axis`` is not a valid axis of ``a``. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ -def ihfft(a: array, /, *, n: Optional[int] = None, axis: int = -1, norm: str = 'backward') -> array: +def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. Parameters ---------- - a: array + x: array input array. Should have a floating-point data type. n: int - length of the transformed axis of the output. If given, the input will be either zero-padded or trimmed to this length before computing the Hermitian Fourier transform. Otherwise, it will default to ``2 * (m - 1)`` where ``m`` is the length of the input along the axis given by the ``axis`` keyword. Default: ``None``. + length of the transformed axis of the output. If + + - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + + if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int - axis used to compute the Fourier transform. If it is not specified, the last axis is used. Default: ``-1``. - norm: str - specify the normalization mode. Should be one of the following modes: + axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: - - ``'backward'``: Normalize by ``1/n``. - - ``'ortho'``: Normalize by ``1/sqrt(n)`` - - ``'forward'``: No normalization. + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'forward'``: no normalization. Default: ``'backward'``. Returns ------- out: array - a transformed array. The returned array must have a complex dtype with the same precision as the input ``x``. - - - **Raises** - - - If ``axis`` is not a valid axis of ``a``. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. """ From 60db5b84b388bba64421e6dd6b2ee080a69011c4 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 1 Aug 2022 15:13:10 -0500 Subject: [PATCH 249/551] fix input/output data types --- .../array_api/fourier_transform_functions.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 94ba48fd0..4d30a985f 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -191,7 +191,7 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a complex floating-point data type. n: int length of the transformed axis of the **output**. If @@ -261,7 +261,7 @@ def irfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Union[Sequence[int], Tuple[int, ...]] size of each transformed axis of the **output**. If @@ -283,7 +283,7 @@ def irfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. """ @@ -294,7 +294,7 @@ def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ Parameters ---------- x: array - input array. Should have a complex floating-point data type. + input array. Should have a real-valued floating-point data type. n: int length of the transformed axis of the output. If @@ -327,7 +327,7 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued floating-point data type. n: int length of the transformed axis of the output. If @@ -349,7 +349,7 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ From 9dc714e6be4f4f385d36c72d2fb0d03feb7ca69b Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 22 Aug 2022 11:59:09 -0700 Subject: [PATCH 250/551] Add complex number support to `tanh` (#458) * Add complex number support to `tanh` * Fix equation * Add warning concerning older C versions --- .../array_api/elementwise_functions.py | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index ed422cc08..2394ea440 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1466,12 +1466,22 @@ def tan(x: array, /) -> array: """ def tanh(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the hyperbolic tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic tangent is + + .. math:: + \begin{align} \operatorname{tanh}(x) &= \frac{\operatorname{sinh}(x)}{\operatorname{cosh}(x)} \\ &= \frac{e^x - e^{-x}}{e^x + e^{-x}} \end{align} + + where :math:`\operatorname{sinh}(x)` is the hyperbolic sine and :math:`\operatorname{cosh}(x)` is the hyperbolic cosine. **Special cases** - For floating-point operands, + .. note:: + For all operands, ``tanh(-x)`` must equal ``-tanh(x)``. + + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. @@ -1479,15 +1489,40 @@ def tanh(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``+1``. - If ``x_i`` is ``-infinity``, the result is ``-1``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``tanh(conj(x))`` must equal ``conj(tanh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``+0 + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``1 + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. warning:: + For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. + + Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. note:: + The hyperbolic tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the imaginary component and has first order poles along the imaginary line at coordinates :math:`(0, \pi (\frac{1}{2} + n))`. However, IEEE 754 binary floating-point representation cannot represent :math:`\pi / 2` exactly, and, thus, no argument value is possible such that a pole error occurs. + Parameters ---------- x: array - input array whose elements each represent a hyperbolic angle. Should have a real-valued floating-point data type. + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. Returns ------- out: array - an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def trunc(x: array, /) -> array: From 733f27c91b963216cf14159435c04d4a3dcce294 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 22 Aug 2022 12:00:19 -0700 Subject: [PATCH 251/551] Add complex number support to `tan` (#459) * Add complex number support to `tan` * Fix linebreak * Fix equation * Update equation --- .../array_api/elementwise_functions.py | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 2394ea440..1c4305d4d 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1442,27 +1442,42 @@ def subtract(x1: array, x2: array, /) -> array: """ def tan(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the tangent, having domain ``(-infinity, +infinity)`` and codomain ``(-infinity, +infinity)``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. + r""" + Calculates an implementation-dependent approximation to the tangent for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. note:: + Tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the real component and has first order poles along the real line at coordinates :math:`(\pi (\frac{1}{2} + n), 0)`. However, IEEE 754 binary floating-point representation cannot represent the value :math:`\pi / 2` exactly, and, thus, no argument value is possible for which a pole error occurs. + + .. note:: + For complex arguments, the mathematical definition of tangent is + + .. math:: + \begin{align} \operatorname{tan}(x) &= \frac{j(e^{-jx} - e^{jx})}{e^{-jx} + e^{jx}} \\ &= (-1) \frac{j(e^{jx} - e^{-jx})}{e^{jx} + e^{-jx}} \\ &= -j \cdot \operatorname{tanh}(jx) \end{align} + + where :math:`\operatorname{tanh}` is the hyperbolic tangent. + Parameters ---------- x: array - input array whose elements are expressed in radians. Should have a real-valued floating-point data type. + input array whose elements are expressed in radians. Should have a floating-point data type. Returns ------- out: array - an array containing the tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def tanh(x: array, /) -> array: From 46e504a73fae643e8c7f12876be770f9f137c2b8 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Tue, 23 Aug 2022 14:18:47 -0500 Subject: [PATCH 252/551] Add review comments --- .../array_api/fourier_transform_functions.py | 166 ++++++++++-------- 1 file changed, 96 insertions(+), 70 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 4d30a985f..9581098f2 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -4,9 +4,8 @@ def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[' """ Computes the one-dimensional discrete Fourier transform. - .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``ifft(fft(x)) == x``. + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. Parameters ---------- @@ -15,19 +14,21 @@ def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[' n: int length of the transformed axis of the output. If - - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. - if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: no normalization. - - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -48,19 +49,21 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ n: int length of the transformed axis of the output. If - - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. - if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int axis (dimension) over which to compute the inverse Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: normalize by ``1/n``. - - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -70,41 +73,42 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ """ -def fftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ Computes the n-dimensional discrete Fourier transform. .. note:: - Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``ifftn(fftn(x)) == x``. + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode.. Parameters ---------- x: array input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + s: Sequence[int] + size of each transformed axis of the output. If - - ``n`` is larger than the length of the input array, the input array must be zero-padded. - - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. + - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be trimmed such that the axis has size``s[i]``. - if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. - s: Union[Sequence[int], Tuple[int, ...]] - size of each transformed axis of the output. If + If ``axes`` is ``None``, the last ``len(s)`` axes must be transformed, and, thus, ``j`` represents an axis index computed according to ``N - len(s) + i``, where ``N`` is the number of axes (e.g., if ``N = 4`` and ``s = (256, 256)``, then ``i = 0`` corresponds to axis ``2`` and ``i = 1`` corresponds to axis ``3``, the last axis). + + If ``axes`` is not ``None``, size ``s[i]`` corresponds to the size of axis ``axes[j]`` where ``i == j``. - - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. - - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. - axes: Union[Sequence[int], Tuple[int, ...]] - axes (dimension) over which to compute the Fourier transform. If set to ``None``, the last ``len(s)`` axes are used, or all axes if ``s`` is set to ``-1``. Default: ``None``. + Default: ``None``. + axes: Sequence[int] + axes (dimension) over which to compute the Fourier transform. If ``None`` and ``s`` is not specified, all axes must be transformed. If ``None`` and ``s`` is specified, the last ``len(s)`` axes must be transformed. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: no normalization. - - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -114,7 +118,7 @@ def fftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: """ -def ifftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ Computes the n-dimensional inverse discrete Fourier transform. @@ -122,22 +126,24 @@ def ifftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: ---------- x: array input array. Should have a floating-point data type. - s: Union[Sequence[int], Tuple[int, ...]] + s: Sequence[int] size of each transformed axis of the output. If - - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. - - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. + - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. - if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. - axes: Union[Sequence[int], Tuple[int, ...]] + If not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. + axes: Sequence[int] axes over which to compute the inverse Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: - ``'backward'``: normalize by ``1/n``. - - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -153,7 +159,7 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``irfft(rfft(x), n=x.shape[axis]) == x``. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode.. Parameters ---------- @@ -162,19 +168,21 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ n: int length of the transformed axis of the **input**. If - - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. - if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: no normalization. - - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -195,19 +203,21 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal n: int length of the transformed axis of the **output**. If - - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n//2+1``. - if not provided, the length of the transformed axis of the output must equal the length ``2 * (m - 1)`` where ``m`` is the length of the input along the axis specified by ``axis``. Default: ``None``. + If not provided, the length of the transformed axis of the output must equal the length ``2 * (m - 1)`` where ``m`` is the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int axis (dimension) over which to compute the inverse Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: normalize by ``1/n``. - - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -217,34 +227,36 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal """ -def rfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ Computes the n-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy: ``irfftn(rfftn(x), n=x.shape[axis]) == x``. + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. Parameters ---------- x: array input array. Should have a real-valued floating-point data type. - s: Union[Sequence[int], Tuple[int, ...]] + s: Sequence[int] size of each transformed axis of the output. If - - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. - - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. + - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. - if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. - axes: Union[Sequence[int], Tuple[int, ...]] + If not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. + axes: Sequence[int] axes over which to compute the Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: no normalization. - - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -254,7 +266,7 @@ def rfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: """ -def irfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes: Union[Sequence[int], Tuple[int, ...]] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ Computes the n-dimensional inverse of ``rfftn``. @@ -262,22 +274,24 @@ def irfftn(x: array, /, *, s: Union[Sequence[int], Tuple[int, ...]] = None, axes ---------- x: array input array. Should have a complex floating-point data type. - s: Union[Sequence[int], Tuple[int, ...]] + s: Sequence[int] size of each transformed axis of the **output**. If - - ``s`` is larger than the length of the input array, each axis ``i`` of the input array must be zero-padded. - - ``s`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. Except for the last axis is trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis. + - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. + - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. Except for the last axis is trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis. - if not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. - axes: Union[Sequence[int], Tuple[int, ...]] + If not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. + axes: Sequence[int] axes over which to compute the inverse Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: normalize by ``1/n``. - - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -298,17 +312,17 @@ def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ n: int length of the transformed axis of the output. If - - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. - if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: no normalization. - - ``'ortho'``: normalize by ``1/sqrt(n)``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. Default: ``'backward'``. @@ -331,19 +345,21 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal n: int length of the transformed axis of the output. If - - ``n`` is larger than the length of the input array, the input array must be zero-padded. + - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. - if not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: - ``'backward'``: normalize by ``1/n``. - - ``'ortho'``: normalize by ``1/sqrt(n)`` + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. + where ``n`` equals ``prod(s)``, the logical FFT size. + Default: ``'backward'``. Returns @@ -355,7 +371,9 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal def fftfreq(n: int, /, *, d: float = 1.0): """ - Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + Returns the discrete Fourier transform sample frequencies. + + For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: .. code-block:: @@ -373,7 +391,7 @@ def fftfreq(n: int, /, *, d: float = 1.0): Returns ------- out: array - an array of length ``n`` containing the sample frequencies. + an array of length ``n`` containing the sample frequencies. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ @@ -399,43 +417,51 @@ def rfftfreq(n: int, /, *, d: float = 1.0): Returns ------- out: array - an array of length ``n`` containing the sample frequencies. + an array of length ``n`` containing the sample frequencies. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ -def fftshift(x: array, /, *, axes: Union[int, Sequence[int], Tuple[int, ...]] = None): +def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): """ - Reorders n-dimensional FTT data to have negative frequency terms first. In this way, the zero-frequency component shifts to the center of the spectrum. Note that ``out[0]`` is the Nyquist component only if the length of the input is even. + Shift the zero-frequency component to the center of the spectrum. + + This function swaps half-spaces for all axes (dimensions) specified by `axes`. + + .. note:: + ``out[0]`` is the Nyquist component only if the length of the input is even. Parameters ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int], Tuple[int, ...]] - axes over which to shift. If not specified, it shifts all axes. Default: ``None``. + axes: Union[int, Sequence[int]] + axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. + the shifted array. The returned array must have the same data type as ``x``. """ -def ifftshift(x: array, /, *, axes: Union[int, Sequence[int], Tuple[int, ...]] = None): +def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): """ Inverse of ``fftshift``. + .. note:: + Although identical for even-length ``x``, ``fftshift`` and `ifftshift`` differ by one sample for odd-length ``x``. + Parameters ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int], Tuple[int, ...]] - axes over which to calculate. If not specified, it shifts all axes. Default: ``None``. + axes: Union[int, Sequence[int]] + axes over which to perform the inverse. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. + the shifted array. The returned array must have the same data type as ``x``. """ From 55b8fb0fd7c0f08d528afcf05e5e2307e61491b4 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Sep 2022 10:19:38 -0700 Subject: [PATCH 253/551] Clarify broadcasting behavior in `vecdot` (#473) This resolves https://github.com/data-apis/array-api/issues/471. The existing spec provides conflicting guidance saying both that the axes over which to compute the dot product must be equal, while also saying that input arrays must be broadcast compatible without qualification, thus implying that the contracted axis could also broadcast. This commit explicitly defines broadcast behavior for only the contracted axes, thus bringing vecdot inline with broadcasting behavior in tensordot. --- .../array_api/linear_algebra_functions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py index 275d91856..1284c9c4e 100644 --- a/spec/API_specification/array_api/linear_algebra_functions.py +++ b/spec/API_specification/array_api/linear_algebra_functions.py @@ -92,14 +92,18 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: x1: array first input array. Should have a real-valued data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + second input array. Should have a real-valued data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + + .. note:: + Contracted axes (dimensions) must not be broadcasted. + axis:int axis over which to compute the dot product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. Returns ------- out: array - if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. The returned array must have a data type determined by :ref:`type-promotion`. + if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. **Raises** From eba54b35b040bb08359fdca7aaeb0340ecb5c87c Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 19 Sep 2022 00:43:34 -0700 Subject: [PATCH 254/551] Add support for broadcasting to `linalg.cross` (#417) * Make explicit that broadcasting only applies to non-compute dimensions in vecdot * Add support for broadcasting to `linalg.cross` * Update copy * Update copy * Fix spacing --- spec/API_specification/array_api/linalg.py | 19 ++++++++++++++++--- .../array_api/linear_algebra_functions.py | 8 ++++---- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index abce23437..5336d93c6 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -41,21 +41,34 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: """ - Returns the cross product of 3-element vectors. If ``x1`` and ``x2`` are multi-dimensional arrays (i.e., both have a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. + Returns the cross product of 3-element vectors. + + If ``x1`` and/or ``x2`` are multi-dimensional arrays (i.e., the broadcasted result has a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. Parameters ---------- x1: array first input array. Should have a real-valued data type. x2: array - second input array. Must have the same shape as ``x1``. Should have a real-valued data type. + second input array. Must be compatible with ``x1`` for all non-compute axes (see :ref:`broadcasting`). The size of the axis over which to compute the cross product must be the same size as the respective axis in ``x1``. Should have a real-valued data type. + + .. note:: + The compute axis (dimension) must not be broadcasted. + axis: int - the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. If set to ``-1``, the function computes the cross product for vectors defined by the last axis (dimension). Default: ``-1``. + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. Returns ------- out: array an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + + + **Raises** + + - if provided an invalid ``axis``. + - if the size of the axis over which to compute the cross product is not equal to ``3``. + - if the size of the axis over which to compute the cross product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ def det(x: array, /) -> array: diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py index 1284c9c4e..f8f15e5b0 100644 --- a/spec/API_specification/array_api/linear_algebra_functions.py +++ b/spec/API_specification/array_api/linear_algebra_functions.py @@ -92,12 +92,12 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: x1: array first input array. Should have a real-valued data type. x2: array - second input array. Should have a real-valued data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). The size of the axis over which to compute the dot product must be the same size as the respective axis in ``x1``. Should have a real-valued data type. .. note:: - Contracted axes (dimensions) must not be broadcasted. + The contracted axis (dimension) must not be broadcasted. - axis:int + axis: int axis over which to compute the dot product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. Returns @@ -109,7 +109,7 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: **Raises** - if provided an invalid ``axis``. - - if the size of the axis over which to compute the dot product is not the same for both ``x1`` and ``x2``. + - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ __all__ = ['matmul', 'matrix_transpose', 'tensordot', 'vecdot'] From be6330a9020c0ae9ae3abbfc4b2a458a64e1cf7e Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 5 Oct 2022 13:57:58 -0400 Subject: [PATCH 255/551] Apply suggestions from code review --- .../array_api/fourier_transform_functions.py | 35 +++++++++---------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 9581098f2..654d24589 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -88,10 +88,9 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no s: Sequence[int] size of each transformed axis of the output. If - - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be trimmed such that the axis has size``s[i]``. + - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``i``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. + - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the corresponding axis of the input array must be trimmed such that the axis has size ``s[i]``. - If ``axes`` is ``None``, the last ``len(s)`` axes must be transformed, and, thus, ``j`` represents an axis index computed according to ``N - len(s) + i``, where ``N`` is the number of axes (e.g., if ``N = 4`` and ``s = (256, 256)``, then ``i = 0`` corresponds to axis ``2`` and ``i = 1`` corresponds to axis ``3``, the last axis). If ``axes`` is not ``None``, size ``s[i]`` corresponds to the size of axis ``axes[j]`` where ``i == j``. @@ -99,7 +98,7 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no Default: ``None``. axes: Sequence[int] - axes (dimension) over which to compute the Fourier transform. If ``None`` and ``s`` is not specified, all axes must be transformed. If ``None`` and ``s`` is specified, the last ``len(s)`` axes must be transformed. Default: ``None``. + axes (dimension) over which to compute the Fourier transform. If ``None`` and ``s`` is not specified, all axes must be transformed. If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -203,8 +202,8 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal n: int length of the transformed axis of the **output**. If - - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n//2+1``. + - ``n//2+1`` is greater than the length of the input array, the input array must be zero-padded. + - ``n//2+1`` is less than the length of the input array, the input array must be trimmed. If not provided, the length of the transformed axis of the output must equal the length ``2 * (m - 1)`` where ``m`` is the length of the input along the axis specified by ``axis``. Default: ``None``. axis: int @@ -343,7 +342,7 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal x: array input array. Should have a real-valued floating-point data type. n: int - length of the transformed axis of the output. If + length of the transformed axis of the **input**. If - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. @@ -365,7 +364,7 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. """ @@ -375,11 +374,10 @@ def fftfreq(n: int, /, *, d: float = 1.0): For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: - .. code-block:: - f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even - f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) # if n is odd Parameters ---------- @@ -397,13 +395,14 @@ def fftfreq(n: int, /, *, d: float = 1.0): def rfftfreq(n: int, /, *, d: float = 1.0): """ - Returns the discrete Fourier transform sample frequencies. For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: - + Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + + For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: .. code-block:: - f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) if n is even - f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) if n is odd + f = [0, 1, ..., n/2-1, n/2] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) # if n is odd The Nyquist frequency component is considered to be positive. @@ -417,7 +416,7 @@ def rfftfreq(n: int, /, *, d: float = 1.0): Returns ------- out: array - an array of length ``n`` containing the sample frequencies. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ @@ -425,7 +424,7 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): """ Shift the zero-frequency component to the center of the spectrum. - This function swaps half-spaces for all axes (dimensions) specified by `axes`. + This function swaps half-spaces for all axes (dimensions) specified by ``axes``. .. note:: ``out[0]`` is the Nyquist component only if the length of the input is even. @@ -449,7 +448,7 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): Inverse of ``fftshift``. .. note:: - Although identical for even-length ``x``, ``fftshift`` and `ifftshift`` differ by one sample for odd-length ``x``. + Although identical for even-length ``x``, ``fftshift`` and ``ifftshift`` differ by one sample for odd-length ``x``. Parameters ---------- From 67ab4748d697ea05e8c89ed653c26849cdd866c0 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 5 Oct 2022 21:51:40 +0100 Subject: [PATCH 256/551] Complex dtype support in `finfo()` (#484) --- .../array_api/data_type_functions.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/array_api/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py index 3731e4c98..93b27cea8 100644 --- a/spec/API_specification/array_api/data_type_functions.py +++ b/spec/API_specification/array_api/data_type_functions.py @@ -46,12 +46,15 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: def finfo(type: Union[dtype, array], /) -> finfo_object: """ - Machine limits for real-valued floating-point data types. + Machine limits for floating-point data types. Parameters ---------- type: Union[dtype, array] - the kind of real-valued floating-point data-type about which to get information. + the kind of floating-point data-type about which to get information. If complex, the information is about its component data type. + + .. note:: + Complex floating-point data types are specified to always use the same precision for both its real and imaginary components, so the information should be true for either component. Returns ------- @@ -60,23 +63,23 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: - **bits**: *int* - number of bits occupied by the floating-point data type. + number of bits occupied by the real-valued floating-point data type. - **eps**: *float* - difference between 1.0 and the next smallest representable floating-point number larger than 1.0 according to the IEEE-754 standard. + difference between 1.0 and the next smallest representable real-valued floating-point number larger than 1.0 according to the IEEE-754 standard. - **max**: *float* - largest representable number. + largest representable real-valued number. - **min**: *float* - smallest representable number. + smallest representable real-valued number. - **smallest_normal**: *float* - smallest positive floating-point number with full precision. + smallest positive real-valued floating-point number with full precision. """ def iinfo(type: Union[dtype, array], /) -> iinfo_object: From d632f24a9d67ad90967154e62398cdfe19fcd370 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 21 Sep 2022 12:18:15 +0100 Subject: [PATCH 257/551] `__array_api_version__` docs --- spec/API_specification/array_api/__init__.py | 6 ++++++ spec/API_specification/index.rst | 1 + spec/API_specification/version.rst | 21 ++++++++++++++++++++ 3 files changed, 28 insertions(+) create mode 100644 spec/API_specification/version.rst diff --git a/spec/API_specification/array_api/__init__.py b/spec/API_specification/array_api/__init__.py index e5de2e49f..350dd9fb0 100644 --- a/spec/API_specification/array_api/__init__.py +++ b/spec/API_specification/array_api/__init__.py @@ -12,3 +12,9 @@ from .statistical_functions import * from .utility_functions import * from . import linalg + + +__array_api_version__: str = "2021.12" +""" +String representing the version of the array API specification which the conforming implementation adheres to. +""" diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index 1d4c9cfef..775344482 100644 --- a/spec/API_specification/index.rst +++ b/spec/API_specification/index.rst @@ -24,3 +24,4 @@ API specification statistical_functions type_promotion utility_functions + version diff --git a/spec/API_specification/version.rst b/spec/API_specification/version.rst new file mode 100644 index 000000000..ab5aa8b44 --- /dev/null +++ b/spec/API_specification/version.rst @@ -0,0 +1,21 @@ +Version +======= + + Array API specification for versioning. + +A conforming implementation of the array API standard must provide a `__array_api_version__` attribute - see :ref:`api-versioning` for details. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + + __array_api_version__ From 8a305c55cfaee97332ab02f85e51cc1ab9f8efed Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 21 Sep 2022 12:26:54 +0100 Subject: [PATCH 258/551] Use `:nosignatures:` for `version.rst` auto-summary --- spec/API_specification/version.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/API_specification/version.rst b/spec/API_specification/version.rst index ab5aa8b44..346395d9a 100644 --- a/spec/API_specification/version.rst +++ b/spec/API_specification/version.rst @@ -17,5 +17,6 @@ Objects in API .. autosummary:: :toctree: generated :template: attribute.rst + :nosignatures: __array_api_version__ From 1b0491be3731b36eae0b71fc6ee0fd320eb3db62 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 6 Oct 2022 12:43:00 +0100 Subject: [PATCH 259/551] Assign `__array_api_version__` stub to `"YYYY.MM" --- spec/API_specification/array_api/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/__init__.py b/spec/API_specification/array_api/__init__.py index 350dd9fb0..50fe5070b 100644 --- a/spec/API_specification/array_api/__init__.py +++ b/spec/API_specification/array_api/__init__.py @@ -14,7 +14,7 @@ from . import linalg -__array_api_version__: str = "2021.12" +__array_api_version__: str = "YYYY.MM" """ String representing the version of the array API specification which the conforming implementation adheres to. """ From cce55e3267b57e5808fcbe202ea2c5757afd70ac Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 23 Sep 2022 10:55:23 +0100 Subject: [PATCH 260/551] `out.dtype` for `finfo()` --- spec/API_specification/array_api/data_type_functions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/API_specification/array_api/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py index 93b27cea8..495bd6002 100644 --- a/spec/API_specification/array_api/data_type_functions.py +++ b/spec/API_specification/array_api/data_type_functions.py @@ -80,6 +80,10 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: - **smallest_normal**: *float* smallest positive real-valued floating-point number with full precision. + + - **dtype**: dtype + + real-valued floating-point data type. """ def iinfo(type: Union[dtype, array], /) -> iinfo_object: From 7f153012618234562ad61c3bbe2f5efa14a69884 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 27 Sep 2022 11:21:10 +0100 Subject: [PATCH 261/551] `out.dtype` for `iinfo()` --- spec/API_specification/array_api/data_type_functions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/spec/API_specification/array_api/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py index 495bd6002..0e07e818c 100644 --- a/spec/API_specification/array_api/data_type_functions.py +++ b/spec/API_specification/array_api/data_type_functions.py @@ -111,6 +111,10 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: - **min**: *int* smallest representable number. + + - **dtype**: dtype + + integer data type. """ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: From c030c0c358ede634d215dd0010d39ff409812be1 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 6 Oct 2022 13:01:43 -0400 Subject: [PATCH 262/551] add round-trip note to relevant fft pairs --- .../array_api/fourier_transform_functions.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 654d24589..86b2aee8b 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -1,5 +1,6 @@ from ._types import Tuple, Union, Sequence, array, Optional, Literal + def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ Computes the one-dimensional discrete Fourier transform. @@ -42,6 +43,9 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ """ Computes the one-dimensional inverse discrete Fourier transform. + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Parameters ---------- x: array @@ -77,9 +81,8 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no """ Computes the n-dimensional discrete Fourier transform. - .. note:: - Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode.. + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. Parameters ---------- @@ -121,6 +124,9 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n """ Computes the n-dimensional inverse discrete Fourier transform. + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Parameters ---------- x: array @@ -156,9 +162,8 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ """ Computes the one-dimensional discrete Fourier transform for real-valued input. - .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode.. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. Parameters ---------- @@ -195,6 +200,9 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal """ Computes the one-dimensional inverse of ``rfft``. + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Parameters ---------- x: array @@ -230,7 +238,6 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n """ Computes the n-dimensional discrete Fourier transform for real-valued input. - .. note:: Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. @@ -269,6 +276,9 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, """ Computes the n-dimensional inverse of ``rfftn``. + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Parameters ---------- x: array From 29da2cdb9b8f8f96ce9d9c79afd86a80eb206618 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 6 Oct 2022 13:54:20 -0400 Subject: [PATCH 263/551] fix s & axes requirement --- .../array_api/fourier_transform_functions.py | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 86b2aee8b..6be779e1c 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -94,14 +94,17 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``i``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the corresponding axis of the input array must be trimmed such that the axis has size ``s[i]``. - - If ``axes`` is not ``None``, size ``s[i]`` corresponds to the size of axis ``axes[j]`` where ``i == j``. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. Default: ``None``. axes: Sequence[int] - axes (dimension) over which to compute the Fourier transform. If ``None`` and ``s`` is not specified, all axes must be transformed. If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. Default: ``None``. + axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -137,9 +140,17 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. - If not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + + If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + + Default: ``None``. axes: Sequence[int] - axes over which to compute the inverse Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. + axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -251,9 +262,17 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. - If not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + + If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + + Default: ``None``. axes: Sequence[int] - axes over which to compute the Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. + axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -289,9 +308,17 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. Except for the last axis is trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis. - If not provided, the length of the transformed axes of the output must equal the length of the input along the axes specified by ``axes``. Default: ``None``. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + + If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + + Default: ``None``. axes: Sequence[int] - axes over which to compute the inverse Fourier transform. If not specified, the last ``len(s)`` axes are used, or all axes if ``s`` is not specified either. Default: ``None``. + axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: From c0c25a1cb00d8f3527f58bed7c9021753d7aa08f Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 6 Oct 2022 22:33:22 -0400 Subject: [PATCH 264/551] improve wording --- .../array_api/fourier_transform_functions.py | 128 ++++++++++-------- 1 file changed, 71 insertions(+), 57 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 6be779e1c..dde4a4e9c 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -15,12 +15,15 @@ def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[' n: int length of the transformed axis of the output. If - - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. + - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. + - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. - If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. + + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -53,12 +56,15 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ n: int length of the transformed axis of the output. If - - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. + - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. + - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. - If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. + + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -91,13 +97,12 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no s: Sequence[int] size of each transformed axis of the output. If - - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``i``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the corresponding axis of the input array must be trimmed such that the axis has size ``s[i]``. + - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. + - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. + - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. - If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - Default: ``None``. axes: Sequence[int] axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. @@ -119,7 +124,7 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determine by :ref:`type-promotion`. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. """ @@ -137,13 +142,12 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n s: Sequence[int] size of each transformed axis of the output. If - - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. + - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. + - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. - If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - Default: ``None``. axes: Sequence[int] axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. @@ -165,7 +169,7 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determine by :ref:`type-promotion`. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. """ @@ -183,12 +187,15 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ n: int length of the transformed axis of the **input**. If - - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. - - If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. + - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. + - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + + Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. + + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -209,7 +216,7 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ - Computes the one-dimensional inverse of ``rfft``. + Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. @@ -221,12 +228,15 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal n: int length of the transformed axis of the **output**. If - - ``n//2+1`` is greater than the length of the input array, the input array must be zero-padded. - - ``n//2+1`` is less than the length of the input array, the input array must be trimmed. - - If not provided, the length of the transformed axis of the output must equal the length ``2 * (m - 1)`` where ``m`` is the length of the input along the axis specified by ``axis``. Default: ``None``. + - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. + - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. + - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + + Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. + + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -241,7 +251,7 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2 * (m - 1)``. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` otherwise. """ @@ -257,14 +267,13 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n x: array input array. Should have a real-valued floating-point data type. s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. + size of each transformed axis of the **input**. If - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. + - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. + - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. Default: ``None``. axes: Sequence[int] @@ -293,7 +302,7 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: """ - Computes the n-dimensional inverse of ``rfftn``. + Computes the n-dimensional inverse of ``rfftn`` for complex-valued input. .. note:: Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. @@ -303,14 +312,13 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, x: array input array. Should have a complex floating-point data type. s: Sequence[int] - size of each transformed axis of the **output**. If - - - ``s[i]`` is greater than the size of the input array along a corresponding axis (dimension) ``j``, the corresponding axis of the input array must be zero-padded such that the axis has size ``s[i]``. - - ``s[i]`` is less than the length of the input array, each axis ``i`` of the input array must be trimmed to the length ``s[i]``. Except for the last axis is trimmed to ``2 * (m - 1)``, where `m` is the length of the input along the axis. + size of each transformed axis of the **output**. ``n=s[i]`` is also the number of input points used along the axis (dimension) ``i``, except for the last axis, where ``n=s[-1]//2+1`` points of the input are used. If - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - ``n`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``n``. + - ``n`` is less than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``n``. + - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array, except for the last axis which is trimmed to ``2*(m-1)``, where `m` is the length of the input along the axis. - If not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. Default: ``None``. axes: Sequence[int] @@ -333,7 +341,7 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2 * (m - 1)``, and all other axes ``s[i]``. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` otherwise, and all other axes ``s[i]``. """ @@ -346,14 +354,17 @@ def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ x: array input array. Should have a real-valued floating-point data type. n: int - length of the transformed axis of the output. If - - - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. + length of the transformed axis of the **output**. If - If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. + - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. + - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + + Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. + + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -381,12 +392,15 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal n: int length of the transformed axis of the **input**. If - - ``n`` is greater than the length of the input array, the input array must be zero-padded such that the input array has length ``n``. - - ``n`` is less than the length of the input array, the input array must be trimmed to length ``n``. - - If not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. Default: ``None``. + - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. + - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. + - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + + Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If set to ``-1``, the function must compute the Fourier transform over the last axis (dimension). Default: ``-1``. + axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. + + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -413,8 +427,8 @@ def fftfreq(n: int, /, *, d: float = 1.0): .. code-block:: - f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) # if n is even - f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) # if n is odd + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) # if n is odd Parameters ---------- From fd66e4405bd9e887ab398f1805f911c9144af981 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 6 Oct 2022 22:38:50 -0400 Subject: [PATCH 265/551] fix input dtype limit --- .../array_api/fourier_transform_functions.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index dde4a4e9c..ad6a6829b 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -210,7 +210,7 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. """ @@ -224,7 +224,7 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Parameters ---------- x: array - input array. Should have a complex floating-point data type. + input array. Should have a complex-valued floating-point data type. n: int length of the transformed axis of the **output**. If @@ -251,7 +251,7 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` otherwise. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` otherwise. """ @@ -296,7 +296,7 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. """ @@ -310,7 +310,7 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, Parameters ---------- x: array - input array. Should have a complex floating-point data type. + input array. Should have a complex-valued floating-point data type. s: Sequence[int] size of each transformed axis of the **output**. ``n=s[i]`` is also the number of input points used along the axis (dimension) ``i``, except for the last axis, where ``n=s[-1]//2+1`` points of the input are used. If @@ -352,7 +352,7 @@ def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. n: int length of the transformed axis of the **output**. If From 15e37c9522b3b98a14048215dbd33a9e44b3b58f Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 10 Oct 2022 12:01:25 -0700 Subject: [PATCH 266/551] Add `real` specification for returning the real component of a complex number (#427) * Add initial stub * Update copy concerning input and output array data types * Update index * Fix missing export --- .../array_api/elementwise_functions.py | 17 ++++++++++++++++- .../API_specification/elementwise_functions.rst | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 1c4305d4d..c0efb6eaf 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1181,6 +1181,21 @@ def pow(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ +def real(x: array, /) -> array: + """ + Returns the real component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + """ + def remainder(x1: array, x2: array, /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. @@ -1567,4 +1582,4 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] \ No newline at end of file +__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'real', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] \ No newline at end of file diff --git a/spec/API_specification/elementwise_functions.rst b/spec/API_specification/elementwise_functions.rst index 02e3d50b6..0da7d0d7c 100644 --- a/spec/API_specification/elementwise_functions.rst +++ b/spec/API_specification/elementwise_functions.rst @@ -73,6 +73,7 @@ Objects in API not_equal positive pow + real remainder round sign From 309d191dc8eab6e6015088d907e6988868ae190e Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 10 Oct 2022 12:20:47 -0700 Subject: [PATCH 267/551] Add `conj` specification for computing the complex conjugate (#446) * Add specification for computing the complex conjugate * Remove config * Update copy --- .../array_api/elementwise_functions.py | 30 ++++++++++++++++++- .../elementwise_functions.rst | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index c0efb6eaf..9cf6772f7 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -401,6 +401,34 @@ def ceil(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ +def conj(x: array, /) -> array: + """ + Returns the complex conjugate for each element ``x_i`` of the input array ``x``. + + For complex numbers of the form + + .. math:: + a + bj + + the complex conjugate is defined as + + .. math:: + a - bj + + Hence, the returned complex conjugates must be computed by negating the imaginary component of each element ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a complex-floating point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + """ + + def cos(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. @@ -1582,4 +1610,4 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'real', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] \ No newline at end of file +__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'conj', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'real', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] diff --git a/spec/API_specification/elementwise_functions.rst b/spec/API_specification/elementwise_functions.rst index 0da7d0d7c..1f6e818a6 100644 --- a/spec/API_specification/elementwise_functions.rst +++ b/spec/API_specification/elementwise_functions.rst @@ -44,6 +44,7 @@ Objects in API bitwise_right_shift bitwise_xor ceil + conj cos cosh divide From 211fa3a91991c48d4509befc7060214cac914522 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Sat, 15 Oct 2022 16:29:09 -0400 Subject: [PATCH 268/551] add placeholder & address nits --- .../array_api/fourier_transform_functions.py | 50 ++++++++----------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index ad6a6829b..e43930748 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -6,7 +6,7 @@ def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[' Computes the one-dimensional discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (length, axis, and normalization mode). Parameters ---------- @@ -31,8 +31,6 @@ def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[' - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. - where ``n`` equals ``prod(s)``, the logical FFT size. - Default: ``'backward'``. Returns @@ -47,7 +45,7 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ Computes the one-dimensional inverse discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same (length, axis, and normalization mode). Parameters ---------- @@ -72,8 +70,6 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. - where ``n`` equals ``prod(s)``, the logical FFT size. - Default: ``'backward'``. Returns @@ -88,7 +84,7 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no Computes the n-dimensional discrete Fourier transform. .. note:: - Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). Parameters ---------- @@ -99,6 +95,7 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. + - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. @@ -117,7 +114,7 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. - where ``n`` equals ``prod(s)``, the logical FFT size. + where ``n = prod(s)`` is the logical FFT size. Default: ``'backward'``. @@ -133,7 +130,7 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n Computes the n-dimensional inverse discrete Fourier transform. .. note:: - Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). Parameters ---------- @@ -144,6 +141,7 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. + - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. @@ -162,7 +160,7 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. - where ``n`` equals ``prod(s)``, the logical FFT size. + where ``n = prod(s)`` is the logical FFT size. Default: ``'backward'``. @@ -178,7 +176,7 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. Parameters ---------- @@ -203,8 +201,6 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. - where ``n`` equals ``prod(s)``, the logical FFT size. - Default: ``'backward'``. Returns @@ -219,7 +215,7 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. Parameters ---------- @@ -244,14 +240,12 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. - where ``n`` equals ``prod(s)``, the logical FFT size. - Default: ``'backward'``. Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` otherwise. + an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). """ @@ -260,7 +254,7 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n Computes the n-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. Parameters ---------- @@ -271,6 +265,7 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. + - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. @@ -289,7 +284,7 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: normalize by ``1/n``. - where ``n`` equals ``prod(s)``, the logical FFT size. + where ``n = prod(s)``, the logical FFT size. Default: ``'backward'``. @@ -305,7 +300,7 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, Computes the n-dimensional inverse of ``rfftn`` for complex-valued input. .. note:: - Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x), n=x.shape[axis]) == x``), provided that the transform and inverse transform are performed with the same normalization mode. + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. Parameters ---------- @@ -316,7 +311,8 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, - ``n`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``n``. - ``n`` is less than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``n``. - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array, except for the last axis which is trimmed to ``2*(m-1)``, where `m` is the length of the input along the axis. + - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). + - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array, except for the last axis which is trimmed to ``2*(m-1)``, where ``m`` is the length of the input along the axis. If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. @@ -334,14 +330,14 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. - where ``n`` equals ``prod(s)``, the logical FFT size. + where ``n = prod(s)`` is the logical FFT size. Default: ``'backward'``. Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` otherwise, and all other axes ``s[i]``. + an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. """ @@ -408,8 +404,6 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). - ``'forward'``: no normalization. - where ``n`` equals ``prod(s)``, the logical FFT size. - Default: ``'backward'``. Returns @@ -440,7 +434,7 @@ def fftfreq(n: int, /, *, d: float = 1.0): Returns ------- out: array - an array of length ``n`` containing the sample frequencies. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ @@ -467,7 +461,7 @@ def rfftfreq(n: int, /, *, d: float = 1.0): Returns ------- out: array - an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ @@ -506,7 +500,7 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): x: array input array. Should have a floating-point data type. axes: Union[int, Sequence[int]] - axes over which to perform the inverse. If ``None``, the function must shift all axes. Default: ``None``. + axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- From e8e0f1bc471c002c6f777f36fd30e7b432294aa0 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Mon, 17 Oct 2022 00:15:05 -0400 Subject: [PATCH 269/551] add missing return type annotation --- .../array_api/fourier_transform_functions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index e43930748..971b4d8b6 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -413,7 +413,7 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal """ -def fftfreq(n: int, /, *, d: float = 1.0): +def fftfreq(n: int, /, *, d: float = 1.0) -> array: """ Returns the discrete Fourier transform sample frequencies. @@ -438,7 +438,7 @@ def fftfreq(n: int, /, *, d: float = 1.0): """ -def rfftfreq(n: int, /, *, d: float = 1.0): +def rfftfreq(n: int, /, *, d: float = 1.0) -> array: """ Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). @@ -465,7 +465,7 @@ def rfftfreq(n: int, /, *, d: float = 1.0): """ -def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): +def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: """ Shift the zero-frequency component to the center of the spectrum. @@ -488,7 +488,7 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): """ -def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None): +def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: """ Inverse of ``fftshift``. From 18bea1550285ef2e8ad5d22ee28b702a49eca509 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Mon, 17 Oct 2022 09:49:44 -0400 Subject: [PATCH 270/551] Change "should" to "must" for R2C transforms --- .../array_api/fourier_transform_functions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fourier_transform_functions.py index 971b4d8b6..4eef946ab 100644 --- a/spec/API_specification/array_api/fourier_transform_functions.py +++ b/spec/API_specification/array_api/fourier_transform_functions.py @@ -181,7 +181,7 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Must have a real-valued floating-point data type. n: int length of the transformed axis of the **input**. If @@ -259,7 +259,7 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Must have a real-valued floating-point data type. s: Sequence[int] size of each transformed axis of the **input**. If @@ -384,7 +384,7 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Must have a real-valued floating-point data type. n: int length of the transformed axis of the **input**. If From 3c0d3eefad2b128614234f15c0c6c288777c7d46 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 2 Nov 2022 00:17:38 -0700 Subject: [PATCH 271/551] Add `imag` specification for returning the imaginary component of a complex number (#496) * Add specification for returning the imaginary component for each element of a complex number array * Update API list --- .../array_api/elementwise_functions.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 9cf6772f7..915dfa79b 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -785,6 +785,21 @@ def greater_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ +def imag(x: array, /) -> array: + """ + Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + """ + def isfinite(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if finite (i.e., not ``NaN`` and not equal to positive or negative infinity). @@ -1610,4 +1625,4 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'conj', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'real', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] +__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'conj', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'imag', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'real', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] From 7572728333ee952623d6d372e08f92e26ce43c7e Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 4 Nov 2022 21:31:35 +0000 Subject: [PATCH 272/551] `fourier_transform_functions.py` -> `fft.py`, update respective uses (#504) --- spec/API_specification/array_api/__init__.py | 1 + .../array_api/{fourier_transform_functions.py => fft.py} | 0 spec/extensions/fourier_transform_functions.rst | 2 +- 3 files changed, 2 insertions(+), 1 deletion(-) rename spec/API_specification/array_api/{fourier_transform_functions.py => fft.py} (100%) diff --git a/spec/API_specification/array_api/__init__.py b/spec/API_specification/array_api/__init__.py index 50fe5070b..610659cd5 100644 --- a/spec/API_specification/array_api/__init__.py +++ b/spec/API_specification/array_api/__init__.py @@ -12,6 +12,7 @@ from .statistical_functions import * from .utility_functions import * from . import linalg +from . import fft __array_api_version__: str = "YYYY.MM" diff --git a/spec/API_specification/array_api/fourier_transform_functions.py b/spec/API_specification/array_api/fft.py similarity index 100% rename from spec/API_specification/array_api/fourier_transform_functions.py rename to spec/API_specification/array_api/fft.py diff --git a/spec/extensions/fourier_transform_functions.rst b/spec/extensions/fourier_transform_functions.rst index d6be0634d..e048dbfad 100644 --- a/spec/extensions/fourier_transform_functions.rst +++ b/spec/extensions/fourier_transform_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: array_api.fourier_transform_functions +.. currentmodule:: array_api.fft .. NOTE: please keep the functions and their inverse together From 2024bd106c1eeeee096a3295f5dc615081be34ed Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 14 Nov 2022 11:26:02 -0800 Subject: [PATCH 273/551] Add support for specifying the output array dtype in `linalg.trace` (#502) * Add support for specifying the output array dtype * Remove kwarg * Revert change * Fix missing type --- spec/API_specification/array_api/linalg.py | 28 +++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 5336d93c6..43cf983e8 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -1,4 +1,4 @@ -from ._types import Literal, Optional, Tuple, Union, Sequence, array +from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype from .constants import inf def cholesky(x: array, /, *, upper: bool = False) -> array: @@ -437,10 +437,20 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Alias for :func:`~array_api.tensordot`. """ -def trace(x: array, /, *, offset: int = 0) -> array: +def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> array: """ Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the sum is ``NaN`` (i.e., ``NaN`` values propagate). + Parameters ---------- x: array @@ -453,6 +463,18 @@ def trace(x: array, /, *, offset: int = 0) -> array: - ``offset < 0``: off-diagonal below the main diagonal. Default: ``0``. + dtype: Optional[dtype] + data type of the returned array. If ``None``, + + - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + + .. note:: + keyword argument is intended to help prevent data type overflows. Returns ------- @@ -463,7 +485,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) - The returned array must have the same data type as ``x``. + The returned array must have a data type as described by the ``dtype`` parameter above. """ def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: From 7a92139173d38295a8cc779fa2569df24c5f1a7d Mon Sep 17 00:00:00 2001 From: Sebastian Berg Date: Mon, 14 Nov 2022 20:27:54 +0100 Subject: [PATCH 274/551] API: Specify that DLPack should use BufferError (#498) * API: Specify that DLPack should use BufferError I would actually like MUST, but since most implementations currently don't actually give a ``BufferError``, writing it as SHOULD instead. First part of closing https://github.com/numpy/numpy/issues/20742 * Fix duplicated word Co-authored-by: Sebastian Berg Co-authored-by: Athan --- spec/API_specification/array_api/array_object.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 94dac2d1d..cc24a3bbe 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -290,6 +290,15 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P ------- capsule: PyCapsule a DLPack capsule for the array. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + Implementations should raise ``BufferError`` when the data cannot + be exported as DLPack (e.g., incompatible dtype or strides). Other + errors are raised when export fails for other reasons (e.g., incorrect + arguments passed or out of memory). + """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: From d5d7c6cc1d72d12957e9d0d71b572a8507c15797 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 16 Nov 2022 12:37:01 -0800 Subject: [PATCH 275/551] Add `take` specification for returning elements of an array along a specified axis (#416) --- spec/API_specification/array_api/__init__.py | 1 + .../array_api/indexing_functions.py | 27 ++++++++++++++++++ spec/API_specification/index.rst | 1 + spec/API_specification/indexing_functions.rst | 28 +++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 spec/API_specification/array_api/indexing_functions.py create mode 100644 spec/API_specification/indexing_functions.rst diff --git a/spec/API_specification/array_api/__init__.py b/spec/API_specification/array_api/__init__.py index 610659cd5..5368c8325 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 * diff --git a/spec/API_specification/array_api/indexing_functions.py b/spec/API_specification/array_api/indexing_functions.py new file mode 100644 index 000000000..65f2c3450 --- /dev/null +++ b/spec/API_specification/array_api/indexing_functions.py @@ -0,0 +1,27 @@ +from ._types import Union, array + +def take(x: array, indices: array, /, *, axis: int) -> array: + """ + Returns elements of an array along an axis. + + .. note:: + 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: 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. + + 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 + 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'] diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index 775344482..bbb96c8a9 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 diff --git a/spec/API_specification/indexing_functions.rst b/spec/API_specification/indexing_functions.rst new file mode 100644 index 000000000..264b787ae --- /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:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + take From 6d88b3f39d82c8207733c93c8b629ad22397ed06 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 16 Nov 2022 23:29:58 +0100 Subject: [PATCH 276/551] Fix mistake in description of return dtype for `matrix_rank` (#510) This was a simple mistake, not discussed in the review for the PR that added `matrix_rank` (gh-128). Closes gh-469 --- spec/API_specification/array_api/linalg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 43cf983e8..b3595e1fa 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -272,7 +272,7 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a Returns ------- out: array - an array containing the ranks. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). """ def matrix_transpose(x: array, /) -> array: From aefec142a9b780020e9cf9a5b317c1cb2163f45e Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 17 Nov 2022 09:55:39 +0100 Subject: [PATCH 277/551] Update type promotion rules for complex dtypes (#491) * Update type promotion rules for complex dtypes - Add a table with promotion rules - Update type promotion lattice diagram Closes gh-477 Closes gh-478 * Update floating-point type promotion table to include complex dtypes * Update type promotion lattice diagram - mixed float/complex * Remove image that is no longer used --- spec/API_specification/type_promotion.rst | 23 ++++++++++++------ .../images/dtype_promotion_complex.png | Bin 10433 -> 0 bytes .../images/dtype_promotion_lattice.png | Bin 65646 -> 39589 bytes 3 files changed, 16 insertions(+), 7 deletions(-) delete mode 100644 spec/_static/images/dtype_promotion_complex.png diff --git a/spec/API_specification/type_promotion.rst b/spec/API_specification/type_promotion.rst index d30f6517c..b742ee422 100644 --- a/spec/API_specification/type_promotion.rst +++ b/spec/API_specification/type_promotion.rst @@ -89,18 +89,27 @@ Mixed unsigned and signed integer type promotion table Floating-point type promotion table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -+--------+----+----+ -| | f4 | f8 | -+========+====+====+ -| **f4** | f4 | f8 | -+--------+----+----+ -| **f8** | f8 | f8 | -+--------+----+----+ ++---------+-----+-----+-----+-----+ +| | f4 | f8 | c8 | c16 | ++=========+=====+=====+=====+=====+ +| **f4** | f4 | f8 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **f8** | f8 | f8 | c16 | c16 | ++---------+-----+-----+-----+-----+ +| **c8** | c8 | c16 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **c16** | c16 | c16 | c16 | c16 | ++---------+-----+-----+-----+-----+ where - **f4**: single-precision (32-bit) floating-point number (i.e., ``float32``) - **f8**: double-precision (64-bit) floating-point number (i.e., ``float64``) +- **c8**: single-precision complex floating-point number (i.e., ``complex64``) + composed of two single-precision (32-bit) floating-point numbers +- **c16**: double-precision complex floating-point number (i.e., ``complex128``) + composed of two double-precision (64-bit) floating-point numbers + Notes ~~~~~ diff --git a/spec/_static/images/dtype_promotion_complex.png b/spec/_static/images/dtype_promotion_complex.png deleted file mode 100644 index 3503b07f56a885d59a397d35ae3cfc164a4909ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10433 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 M3RNk(WBK?00t!l|VgLXD diff --git a/spec/_static/images/dtype_promotion_lattice.png b/spec/_static/images/dtype_promotion_lattice.png index 669d3047683d4e149ee03f560bc33093d76977a1..4d384ac1559df96f61da2858d85ce01dca496f82 100644 GIT binary patch literal 39589 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 E0695hQ~&?~ literal 65646 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 Date: Thu, 17 Nov 2022 02:30:10 -0800 Subject: [PATCH 278/551] Add complex number support to `expm1` (#452) * Add complex number support to `expm1` * Update copy * Add note concerning complex conjugation * Specify special cases in terms of `cis` function * Fix special cases and move note * Move note * Move note --- .../array_api/elementwise_functions.py | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 915dfa79b..604d11e55 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -607,9 +607,6 @@ def exp(x: array, /) -> array: For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - .. note:: - For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``1 + 0j``. - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. @@ -626,6 +623,9 @@ def exp(x: array, /) -> array: where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + .. note:: The exponential function is an entire function in the complex plane and has no branch cuts. @@ -642,14 +642,14 @@ def exp(x: array, /) -> array: def expm1(x: array, /) -> array: """ - Calculates an implementation-dependent approximation to ``exp(x)-1``, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +infinity]``, for each element ``x_i`` of the input array ``x``. + Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. .. note:: The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. @@ -657,15 +657,39 @@ def expm1(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - If ``x_i`` is ``-infinity``, the result is ``-1``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``0 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b) - 1.0``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the evaluated result for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def floor(x: array, /) -> array: From 1229f06f99586c61db736d797bc5a57f2ff56c0c Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 17 Nov 2022 02:44:17 -0800 Subject: [PATCH 279/551] Fix description for `trunc` (#511) --- spec/API_specification/array_api/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 604d11e55..78a60de9c 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1624,7 +1624,7 @@ def tanh(x: array, /) -> array: def trunc(x: array, /) -> array: """ - Rounds each element ``x_i`` of the input array ``x`` to the integer-valued number that is closest to but no greater than ``x_i``. + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. **Special cases** From cb2d7bdabf8093e863a868a2b25e4450fbda3be8 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 17 Nov 2022 04:49:58 -0700 Subject: [PATCH 280/551] Clarify the required semantics for broadcasting with `__setitem__` (#429) Closes gh-424 --- spec/API_specification/broadcasting.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/broadcasting.rst b/spec/API_specification/broadcasting.rst index ec72fb089..abb3ed222 100644 --- a/spec/API_specification/broadcasting.rst +++ b/spec/API_specification/broadcasting.rst @@ -112,4 +112,17 @@ The following examples demonstrate array shapes which do **not** broadcast. In-place Semantics ------------------ -As implied by the broadcasting algorithm, in-place element-wise operations must not change the shape of the in-place array as a result of broadcasting. +As implied by the broadcasting algorithm, in-place element-wise operations (including ``__setitem__``) must not change the shape of the in-place array as a result of broadcasting. Such operations should only be supported in the case where the right-hand operand can broadcast to the shape of the left-hand operand, after any indexing operations are performed. + +For example: + +:: + + x = empty((2, 3, 4)) + a = empty((1, 3, 4)) + + # This is OK. The shape of a, (1, 3, 4), can broadcast to the shape of x[...], (2, 3, 4) + x[...] = a + + # This is not allowed. The shape of a, (1, 3, 4), can NOT broadcast to the shape of x[1, ...], (3, 4) + x[1, ...] = a From 1b4c218e201f9e06946ad2ecf3382cf1dc20a685 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 19 Nov 2022 19:22:26 -0800 Subject: [PATCH 281/551] Add complex number support to `astype` (#445) * Add complex number support to `astype` * Update note * Disallow casting a complex floating-point data type to a real-valued data type --- .../array_api/data_type_functions.py | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py index 0e07e818c..ad31d099c 100644 --- a/spec/API_specification/array_api/data_type_functions.py +++ b/spec/API_specification/array_api/data_type_functions.py @@ -8,10 +8,20 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: Casting floating-point ``NaN`` and ``infinity`` values to integral data types is not specified and is implementation-dependent. .. note:: - When casting a boolean input array to a real-valued data type, a value of ``True`` must cast to a numeric value equal to ``1``, and a value of ``False`` must cast to a numeric value equal to ``0``. + Casting a complex floating-point array to a real-valued data type should not be permitted. + Historically, when casting a complex floating-point array to a real-valued data type, libraries such as NumPy have discarded imaginary components such that, for a complex floating-point array ``x``, ``astype(x)`` equals ``astype(real(x))``). This behavior is considered problematic as the choice to discard the imaginary component is arbitrary and introduces more than one way to achieve the same outcome (i.e., for a complex floating-point array ``x``, ``astype(x)`` and ``astype(real(x))`` versus only ``astype(imag(x))``). Instead, in order to avoid ambiguity and to promote clarity, this specification requires that array API consumers explicitly express which component should be cast to a specified real-valued data type. + + .. note:: + When casting a boolean input array to a real-valued data type, a value of ``True`` must cast to a real-valued number equal to ``1``, and a value of ``False`` must cast to a real-valued number equal to ``0``. + + When casting a boolean input array to a complex floating-point data type, a value of ``True`` must cast to a complex number equal to ``1 + 0j``, and a value of ``False`` must cast to a complex number equal to ``0 + 0j``. + + .. note:: When casting a real-valued input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. + When casting a complex floating-point array to ``bool``, a value of ``0 + 0j`` must cast to ``False``, and all other values must cast to ``True``. + Parameters ---------- x: array @@ -19,7 +29,7 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: dtype: dtype desired data type. copy: bool - specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated must be returned. Default: ``True``. + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. Returns ------- From 0184f1cc663fb2b97676fd89722cfd80049d23e9 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 21 Nov 2022 11:17:50 -0800 Subject: [PATCH 282/551] Update guidance concerning mixing arrays with Python scalars to handle `complex` (#513) --- spec/API_specification/type_promotion.rst | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/type_promotion.rst b/spec/API_specification/type_promotion.rst index b742ee422..fc9f6e1bf 100644 --- a/spec/API_specification/type_promotion.rst +++ b/spec/API_specification/type_promotion.rst @@ -123,7 +123,7 @@ Notes Mixing arrays with Python scalars ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Using Python scalars (i.e., instances of ``bool``, ``int``, ``float``) together with arrays must be supported for: +Using Python scalars (i.e., instances of ``bool``, ``int``, ``float``, ``complex``) together with arrays must be supported for: - ``array scalar`` - ``scalar array`` @@ -132,7 +132,8 @@ where ```` is a built-in operator (including in-place operators, but excludi - a Python ``bool`` for a ``bool`` array data type. - a Python ``int`` within the bounds of the given data type for integer array :ref:`data-types`. -- a Python ``int`` or ``float`` for floating-point array data types. +- a Python ``int`` or ``float`` for real-valued floating-point array data types. +- a Python ``int``, ``float``, or ``complex`` for complex floating-point array data types. Provided the above requirements are met, the expected behavior is equivalent to: @@ -142,4 +143,6 @@ Provided the above requirements are met, the expected behavior is equivalent to: .. note:: Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. - The behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. + Similarly, behavior is not specified when mixing a Python ``complex`` and an array with a real-valued data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. + + Behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. From cc5b5afb4469fe431aa426b66263b008c3285c00 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 26 Nov 2022 16:45:01 -0800 Subject: [PATCH 283/551] Add complex number support to `sqrt` (#461) * Add complex number support to `sqrt` * Fix missing parenthesis * Move definition of branch cut to definition list * Update description and reorder notes * Update intervals * Add warning concerning provisional status * Fix formatting * Create separate document describing branch cuts and specification conventions * Convert text to italtic * Fix markup * Fix nested directive * Update copy --- .../array_api/elementwise_functions.py | 37 ++++++++++++++++--- spec/design_topics/branch_cuts.rst | 17 +++++++++ spec/design_topics/index.rst | 1 + spec/purpose_and_scope.md | 3 ++ 4 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 spec/design_topics/branch_cuts.rst diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 78a60de9c..e76be8d65 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1482,12 +1482,15 @@ def square(x: array, /) -> array: """ def sqrt(x: array, /) -> array: - """ - Calculates the square root, having domain ``[0, +infinity]`` and codomain ``[0, +infinity]``, for each element ``x_i`` of the input array ``x``. After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). + r""" + Calculates the principal square root for each element ``x_i`` of the input array ``x``. + + .. note:: + After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is less than ``0``, the result is ``NaN``. @@ -1495,15 +1498,39 @@ def sqrt(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. + + .. note:: + By convention, the branch cut of the square root is the negative real axis :math:`(-\infty, 0)`. + + The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the square root of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def subtract(x1: array, x2: array, /) -> array: diff --git a/spec/design_topics/branch_cuts.rst b/spec/design_topics/branch_cuts.rst new file mode 100644 index 000000000..6989afbc7 --- /dev/null +++ b/spec/design_topics/branch_cuts.rst @@ -0,0 +1,17 @@ +.. _branch-cuts: + +Branch Cuts +=========== + +In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. + +For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. + +Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. + +In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. + +.. warning:: + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. \ No newline at end of file diff --git a/spec/design_topics/index.rst b/spec/design_topics/index.rst index 2729cdbe4..c8c55b3be 100644 --- a/spec/design_topics/index.rst +++ b/spec/design_topics/index.rst @@ -11,5 +11,6 @@ Design topics & constraints device_support static_typing accuracy + branch_cuts C_API parallelism diff --git a/spec/purpose_and_scope.md b/spec/purpose_and_scope.md index fc8433c7f..62e9bb8ba 100644 --- a/spec/purpose_and_scope.md +++ b/spec/purpose_and_scope.md @@ -434,6 +434,9 @@ a (usually fixed-size) multidimensional container of items of the same type and **axis**: an array dimension. +**branch cut**: +a curve in the complex plane across which a given complex function fails to be continuous. + **broadcast**: automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. From 19ef83033a4190ea7524b0408953f076bd43f423 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 28 Nov 2022 07:19:02 -0800 Subject: [PATCH 284/551] Add specification for `isdtype` (#503) --- .../array_api/data_type_functions.py | 39 ++++++++++++++++++- .../API_specification/data_type_functions.rst | 1 + 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py index ad31d099c..6b1b242ae 100644 --- a/spec/API_specification/array_api/data_type_functions.py +++ b/spec/API_specification/array_api/data_type_functions.py @@ -1,4 +1,4 @@ -from ._types import Union, array, dtype, finfo_object, iinfo_object +from ._types import Union, Tuple, array, dtype, finfo_object, iinfo_object def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: """ @@ -127,6 +127,41 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: integer data type. """ +def isdtype(dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]]) -> bool: + """ + Returns a boolean indicating whether a provided dtype is of a specified data type "kind". + + Parameters + ---------- + dtype: dtype + the input dtype. + kind: Union[str, dtype, Tuple[Union[str, dtype], ...]] + data type kind. + + - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. + - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: + + - **bool**: boolean data types (e.g., ``bool``). + - **signed integer**: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - **unsigned integer**: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - **integral**: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - **real floating**: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - **complex floating**: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - **numeric**: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. + + .. note:: + A conforming implementation of the array API standard is **not** limited to only including the dtypes described in this specification in the required data type kinds. For example, implementations supporting ``float16`` and ``bfloat16`` can include ``float16`` and ``bfloat16`` in the ``real floating`` data type kind. Similarly, implementations supporting ``int128`` can include ``int128`` in the ``signed integer`` data type kind. + + In short, conforming implementations may extend data type kinds; however, data type kinds must remain consistent (e.g., only integer dtypes may belong to integer data type kinds and only floating-point dtypes may belong to floating-point data type kinds), and extensions must be clearly documented as such in library documentation. + + Returns + ------- + out: bool + boolean indicating whether a provided dtype is of a specified data type kind. + """ + def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: """ Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. @@ -145,4 +180,4 @@ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: the dtype resulting from an operation involving the input arrays and dtypes. """ -__all__ = ['astype', 'can_cast', 'finfo', 'iinfo', 'result_type'] +__all__ = ['astype', 'can_cast', 'finfo', 'iinfo', 'isdtype', 'result_type'] diff --git a/spec/API_specification/data_type_functions.rst b/spec/API_specification/data_type_functions.rst index d58e438a9..d42968c7b 100644 --- a/spec/API_specification/data_type_functions.rst +++ b/spec/API_specification/data_type_functions.rst @@ -22,4 +22,5 @@ Objects in API can_cast finfo iinfo + isdtype result_type From 177675caaf91872fb31e99dafce0e0864e343ad8 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 28 Nov 2022 16:20:08 +0100 Subject: [PATCH 285/551] Add a note on data types possibly not being the same across devices (#515) Closes gh-508 --- spec/API_specification/data_types.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/API_specification/data_types.rst b/spec/API_specification/data_types.rst index 2ab926653..a9be88181 100644 --- a/spec/API_specification/data_types.rst +++ b/spec/API_specification/data_types.rst @@ -130,6 +130,11 @@ The default integer data type should be the same across platforms, but the defau The default array index data type may be ``int32`` on 32-bit platforms, but the default should be ``int64`` otherwise. +Note that it is possible that a library supports multiple devices, with not all +those device types supporting the same data types. In this case, the default +integer or floating-point data types may vary with device. If that is the case, +the library should clearly warn about this in its documentation. + .. note:: The default data types should be clearly defined in a conforming library's documentation. From d5f252bf25964d0e065fad0c25579f8625271251 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 28 Nov 2022 16:26:21 +0100 Subject: [PATCH 286/551] Describe what extensions are and how to use themo (#470) Note that an alternative idea discussed earlier was a separate function `get_extension()`, but IIRC that was not considered a good idea. Now that we have module-level `__getattr__`'s, it should not be a problem for any library to use a specified name like `linalg` or `fft`. Whether the functions in the `linalg` extensions should all be required to exist or not was discussed in gh-403 (no clear conclusion there). One option discussed there to deal with hard to implement or more niche APIs is to create a separate status/label or some other way to track desired signatures (details to be worked out if we want to go that way). --- spec/extensions/index.rst | 25 ++++++++++++++++++-- spec/extensions/linear_algebra_functions.rst | 17 +++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/spec/extensions/index.rst b/spec/extensions/index.rst index 7fe36f3ad..706820f3b 100644 --- a/spec/extensions/index.rst +++ b/spec/extensions/index.rst @@ -3,9 +3,30 @@ Extensions ========== +Extensions are coherent sets of functionality that are commonly implemented +across array libraries. Each array library supporting this standard may, but is +not required to, implement an extension. If an extension is supported, it +must be accessible inside the main array API supporting namespace as a separate +namespace. + +Extension module implementors must aim to provide all functions and other +public objects in an extension. The rationale for this is that downstream usage +can then check whether or not the extension is present (using ``hasattr(xp, +'extension_name')`` should be enough), and can then assume that functions are +implemented. This in turn makes it also easy for array-consuming libraries to +document which array libraries they support - e.g., "all libraries implementing +the array API standard and its linear algebra extension". + +The mechanism through which the extension namespace is made available is up to +the implementer, e.g. via a regular submodule that is imported under the +``linalg`` name, or via a module-level ``__getattr__``. + + +Extensions +---------- + .. toctree:: - :caption: Extensions - :maxdepth: 3 + :maxdepth: 1 fourier_transform_functions linear_algebra_functions diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/extensions/linear_algebra_functions.rst index dbe643bed..c91ce021d 100644 --- a/spec/extensions/linear_algebra_functions.rst +++ b/spec/extensions/linear_algebra_functions.rst @@ -5,6 +5,23 @@ Linear Algebra Extension Array API specification for linear algebra functions. +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``linalg``. + +If implemented, this ``linalg`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'linalg'): + >>> # Use `xp.linalg` + + +General syntax and semantics rules +---------------------------------- + +.. TODO: get rid of this here, it's duplicated over and over + 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. From dc98c2553f8aa507d2a3ed4e29180577f0ae1284 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Mon, 28 Nov 2022 10:37:38 -0500 Subject: [PATCH 287/551] Add `device` keyword to fftfreq and rfftfreq (#506) Co-authored-by: Athan Co-authored-by: Ralf Gommers --- spec/API_specification/array_api/fft.py | 58 +++++++++++++------------ 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/spec/API_specification/array_api/fft.py b/spec/API_specification/array_api/fft.py index 4eef946ab..ac292ceb9 100644 --- a/spec/API_specification/array_api/fft.py +++ b/spec/API_specification/array_api/fft.py @@ -1,4 +1,4 @@ -from ._types import Tuple, Union, Sequence, array, Optional, Literal +from ._types import Tuple, Union, Sequence, array, Optional, Literal, device def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: @@ -22,7 +22,7 @@ def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[' Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -61,7 +61,7 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ Default: ``None``. axis: int axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -98,14 +98,14 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. Default: ``None``. axes: Sequence[int] axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -144,14 +144,14 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. Default: ``None``. axes: Sequence[int] axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -188,11 +188,11 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. - + Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -227,11 +227,11 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. - + Default: ``None``. axis: int axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -273,10 +273,10 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n Default: ``None``. axes: Sequence[int] axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - - Default: ``None``. + + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -319,10 +319,10 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, Default: ``None``. axes: Sequence[int] axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - + If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - - Default: ``None``. + + Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -355,11 +355,11 @@ def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. - + Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -391,11 +391,11 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. - + Default: ``None``. axis: int axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - + Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -413,7 +413,7 @@ def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal """ -def fftfreq(n: int, /, *, d: float = 1.0) -> array: +def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ Returns the discrete Fourier transform sample frequencies. @@ -430,6 +430,8 @@ def fftfreq(n: int, /, *, d: float = 1.0) -> array: window length. d: float sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + device: Optional[device] + device on which to place the created array. Default: ``None``. Returns ------- @@ -438,10 +440,10 @@ def fftfreq(n: int, /, *, d: float = 1.0) -> array: """ -def rfftfreq(n: int, /, *, d: float = 1.0) -> array: +def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). - + Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: .. code-block:: @@ -457,6 +459,8 @@ def rfftfreq(n: int, /, *, d: float = 1.0) -> array: window length. d: float sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + device: Optional[device] + device on which to place the created array. Default: ``None``. Returns ------- From 57d60ce490eab54d51139a2bef926407c0794104 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:23:00 -0800 Subject: [PATCH 288/551] Add complex number support to `atan` (#523) --- .../array_api/elementwise_functions.py | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index e76be8d65..e64994607 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -167,12 +167,14 @@ def asinh(x: array, /) -> array: """ def atan(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation of the principal value of the inverse tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-π/2, +π/2]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. @@ -180,15 +182,33 @@ def atan(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. note:: + The principal value of the inverse tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atan}(z) = -\frac{\ln(1 - zj) - \ln(1 + zj)}{2}j + + .. note:: + For complex floating-point operands, ``atan(conj(x))`` must equal ``conj(atan(x))``. + + .. note:: + The inverse tangent (or arc tangent) is a multi-valued function and requires a branch on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(+j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse tangent in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the inverse tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def atan2(x1: array, x2: array, /) -> array: From b5e6af0431c94d814317714d49891e1eb9c31320 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:23:46 -0800 Subject: [PATCH 289/551] Add complex number support to `atanh` (#524) --- .../array_api/elementwise_functions.py | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index e64994607..fdc3b6e8f 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -265,12 +265,12 @@ def atan2(x1: array, x2: array, /) -> array: """ def atanh(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the inverse hyperbolic tangent, having domain ``[-1, +1]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element ``x_i`` of the input array ``x``. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is less than ``-1``, the result is ``NaN``. @@ -280,15 +280,50 @@ def atanh(x: array, /) -> array: - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``1`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + The principal value of the inverse hyperbolic tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atanh}(z) = \frac{\ln(1+z)-\ln(z-1)}{2} + + For any :math:`z`, + + .. math:: + \operatorname{atanh}(z) = \frac{\operatorname{atan}(zj)}{j} + + .. note:: + For complex floating-point operands, ``atanh(conj(x))`` must equal ``conj(atanh(x))`` and ``atanh(-x)`` must equal ``-atanh(x)``. + + .. note:: + The inverse hyperbolic tangent is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, 1]` and :math:`[1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic tangent in the range of a half-strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array whose elements each represent the area of a hyperbolic sector. Should have a real-valued floating-point data type. + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. Returns ------- out: array - an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def bitwise_and(x1: array, x2: array, /) -> array: From c1fbd4d3727410c0fba76dd89ba1abb5feb874b0 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:26:15 -0800 Subject: [PATCH 290/551] Add complex support to `asinh` (#522) --- .../array_api/elementwise_functions.py | 43 ++++++++++++++++--- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index fdc3b6e8f..c25f3634f 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -142,12 +142,12 @@ def asin(x: array, /) -> array: """ def asinh(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the inverse hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. @@ -155,15 +155,48 @@ def asinh(x: array, /) -> array: - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + The principal value of the inverse hyperbolic sine of a complex number :math:`z` is + + .. math:: + \operatorname{asinh}(z) = \ln(z + \sqrt{1+z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asinh}(z) = \frac{\operatorname{asin}(zj)}{j} + + .. note:: + For complex floating-point operands, ``asinh(conj(x))`` must equal ``conj(asinh(x))`` and ``asinh(-z)`` must equal ``-asinh(z)``. + + .. note:: + The inverse hyperbolic sine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic sine in the range of a strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array whose elements each represent the area of a hyperbolic sector. Should have a real-valued floating-point data type. + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. Returns ------- out: array - an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def atan(x: array, /) -> array: From 1d1833f0ae7badcfbe54085867d83f293ea17e92 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:26:37 -0800 Subject: [PATCH 291/551] Add complex support to `asin` (#521) --- .../array_api/elementwise_functions.py | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index c25f3634f..1d2cf1c3d 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -117,12 +117,14 @@ def add(x1: array, x2: array, /) -> array: """ def asin(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation of the principal value of the inverse sine, having domain ``[-1, +1]`` and codomain ``[-π/2, +π/2]`` for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is greater than ``1``, the result is ``NaN``. @@ -130,15 +132,38 @@ def asin(x: array, /) -> array: - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. note:: + The principal value of the arc sine of a complex number :math:`z` is + + .. math:: + \operatorname{asin}(z) = -j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asin}(z) = \operatorname{acos}(-z) - \frac{\pi}{2} + + .. note:: + For complex floating-point operands, ``asin(conj(x))`` must equal ``conj(asin(x))``. + + .. note:: + The inverse sine (or arc sine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse sine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the inverse sine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def asinh(x: array, /) -> array: From f32ec6b2495386a3c81e5b0130b8bae4a4a6d4dd Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:27:13 -0800 Subject: [PATCH 292/551] Add complex support to `acosh` (#520) --- .../array_api/elementwise_functions.py | 53 +++++++++++++++++-- 1 file changed, 48 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 1d2cf1c3d..203718ab9 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -51,27 +51,70 @@ def acos(x: array, /) -> array: """ def acosh(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the inverse hyperbolic cosine, having domain ``[+1, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is less than ``1``, the result is ``NaN``. - If ``x_i`` is ``1``, the result is ``+0``. - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + πj/2``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN ± πj/2`` (sign of imaginary component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + The principal value of the inverse hyperbolic cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acosh}(z) = \ln(z + \sqrt{z+1}\sqrt{z-1}) + + For any :math:`z`, + + .. math:: + \operatorname{acosh}(z) = \frac{\sqrt{z-1}}{\sqrt{1-z}}\operatorname{acos}(z) + + or simply + + .. math:: + \operatorname{acosh}(z) = j\ \operatorname{acos}(z) + + in the upper half of the complex plane. + + .. note:: + For complex floating-point operands, ``acosh(conj(x))`` must equal ``conj(acosh(x))``. + + .. note:: + The inverse hyperbolic cosine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segment :math:`(-\infty, 1)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic cosine in the interval :math:`[0, \infty)` along the real axis and in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array whose elements each represent the area of a hyperbolic sector. Should have a real-valued floating-point data type. + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. Returns ------- out: array - an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def add(x1: array, x2: array, /) -> array: From 247f082937d8f135c7bc02f49eb74f7574d625e3 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:27:38 -0800 Subject: [PATCH 293/551] Add complex number support to `acos` (#517) --- .../array_api/elementwise_functions.py | 48 +++++++++++++++++-- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 203718ab9..8c32e7674 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -27,27 +27,65 @@ def abs(x: array, /) -> array: """ def acos(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation of the principal value of the inverse cosine, having domain ``[-1, +1]`` and codomain ``[+0, +π]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is greater than ``1``, the result is ``NaN``. - If ``x_i`` is less than ``-1``, the result is ``NaN``. - If ``x_i`` is ``1``, the result is ``+0``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``. + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + The principal value of the arc cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acos}(z) = \frac{1}{2}\pi + j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{acos}(z) = \pi - \operatorname{acos}(-z) + + .. note:: + For complex floating-point operands, ``acos(conj(x))`` must equal ``conj(acos(x))``. + + .. note:: + The inverse cosine (or arc cosine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \pi]` along the real axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the inverse cosine of each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def acosh(x: array, /) -> array: From 857e6adb3565e69f82c154759e8a41c8c6b05064 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:34:57 -0800 Subject: [PATCH 294/551] Add design document on complex number ordering (#527) --- .../array_api/array_object.py | 12 ++++++++++++ .../array_api/elementwise_functions.py | 12 ++++++++++++ .../array_api/searching_functions.py | 14 ++++++++++++-- .../array_api/sorting_functions.py | 10 ++++++++-- .../array_api/statistical_functions.py | 6 ++++++ .../design_topics/complex_number_ordering.rst | 19 +++++++++++++++++++ spec/design_topics/index.rst | 1 + 7 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 spec/design_topics/complex_number_ordering.rst diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index cc24a3bbe..600851569 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -427,6 +427,9 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- self: array @@ -465,6 +468,9 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- self: array @@ -538,6 +544,9 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- self: array @@ -580,6 +589,9 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- self: array diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 8c32e7674..00c71c353 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -973,6 +973,9 @@ def greater(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- x1: array @@ -990,6 +993,9 @@ def greater_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- x1: array @@ -1067,6 +1073,9 @@ def less(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- x1: array @@ -1084,6 +1093,9 @@ def less_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- x1: array diff --git a/spec/API_specification/array_api/searching_functions.py b/spec/API_specification/array_api/searching_functions.py index a76b03f63..1db08f287 100644 --- a/spec/API_specification/array_api/searching_functions.py +++ b/spec/API_specification/array_api/searching_functions.py @@ -2,7 +2,12 @@ def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ - Returns the indices of the maximum values along a specified axis. When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + Returns the indices of the maximum values along a specified axis. + + When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). Parameters ---------- @@ -21,7 +26,12 @@ def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ - Returns the indices of the minimum values along a specified axis. When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + Returns the indices of the minimum values along a specified axis. + + When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). Parameters ---------- diff --git a/spec/API_specification/array_api/sorting_functions.py b/spec/API_specification/array_api/sorting_functions.py index 715a3e817..53732d535 100644 --- a/spec/API_specification/array_api/sorting_functions.py +++ b/spec/API_specification/array_api/sorting_functions.py @@ -4,10 +4,13 @@ def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bo """ Returns the indices that sort an array ``x`` along a specified axis. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- x : array - input array. + input array. Should have a real-valued data type. axis: int axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. descending: bool @@ -25,10 +28,13 @@ def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool """ Returns a sorted copy of an input array ``x``. + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + Parameters ---------- x: array - input array. + input array. Should have a real-valued data type. axis: int axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. descending: bool diff --git a/spec/API_specification/array_api/statistical_functions.py b/spec/API_specification/array_api/statistical_functions.py index 6cdbbb338..9ef10060d 100644 --- a/spec/API_specification/array_api/statistical_functions.py +++ b/spec/API_specification/array_api/statistical_functions.py @@ -7,6 +7,9 @@ def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep .. note:: When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, @@ -64,6 +67,9 @@ def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep .. note:: When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, diff --git a/spec/design_topics/complex_number_ordering.rst b/spec/design_topics/complex_number_ordering.rst new file mode 100644 index 000000000..25ad215cd --- /dev/null +++ b/spec/design_topics/complex_number_ordering.rst @@ -0,0 +1,19 @@ +.. _complex-number-ordering: + +Complex Number Ordering +======================= + +Given a set :math:`\{a_1, \ldots, a_n\}`, an order relation must satisfy the following properties: + +1. **Reflexive**: for any :math:`a` in the set, :math:`a \leq a`. +2. **Transitive**: for any :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`b \leq c`, then :math:`a \leq c`. +3. **Antisymmetric**: for any :math:`a` and :math:`b` in the set, if :math:`a \leq b` and :math:`b \leq a`, then :math:`a = b`. +4. **Total Order**: in addition to the *partial order* established by 1-3, for any :math:`a` and :math:`b` in the set, either :math:`a \leq b` or :math:`b \leq a` (or both). +5. **Compatible with Addition**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b`, then :math:`a + c \leq b + c`. +6. **Compatible with Multiplication**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`0 \leq c`, then :math:`ac \leq bc`. + +Defining an order relation for complex numbers which satisfies all six properties defined above is not possible. Accordingly, this specification does not require that a conforming implementation of the array API standard adopt any specific complex number order relation. + +In order to satisfy backward compatibility guarantees, conforming implementations of the array API standard may choose to define an ordering for complex numbers (e.g., lexicographic); however, consumers of the array API standard should **not** assume that complex number ordering is consistent between implementations or even supported. + +If a conforming implementation chooses to define an ordering for complex numbers, the ordering must be clearly documented. \ No newline at end of file diff --git a/spec/design_topics/index.rst b/spec/design_topics/index.rst index c8c55b3be..55b9d74b4 100644 --- a/spec/design_topics/index.rst +++ b/spec/design_topics/index.rst @@ -12,5 +12,6 @@ Design topics & constraints static_typing accuracy branch_cuts + complex_number_ordering C_API parallelism From 6e0c630c745717a5224a4beec399bf1c86711190 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:44:45 -0800 Subject: [PATCH 295/551] Add complex number support to `isnan` (#532) --- .../array_api/elementwise_functions.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 00c71c353..cd64dfa18 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1058,15 +1058,27 @@ def isnan(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` or ``b`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- out: array - an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is ``NaN`` and ``False`` otherwise. The returned array should have a data type of ``bool``. + an array containing test results. The returned array should have a data type of ``bool``. """ def less(x1: array, x2: array, /) -> array: From f81cc32fbd9cea5d02462519e485cd40ae33c529 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:46:18 -0800 Subject: [PATCH 296/551] Add complex number support to `isinf` (#530) --- .../array_api/elementwise_functions.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index cd64dfa18..024689c33 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1043,15 +1043,28 @@ def isinf(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. + - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- out: array - an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is either positive or negative infinity and ``False`` otherwise. The returned array must have a data type of ``bool``. + an array containing test results. The returned array must have a data type of ``bool``. """ def isnan(x: array, /) -> array: From 74eb0891f8c2fc2493c60dd0fb6434eb193a45a1 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 5 Dec 2022 08:47:15 -0800 Subject: [PATCH 297/551] Add complex number support to `isfinite` (#531) --- .../array_api/elementwise_functions.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 024689c33..c68076aa0 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1026,17 +1026,32 @@ def imag(x: array, /) -> array: def isfinite(x: array, /) -> array: """ - Tests each element ``x_i`` of the input array ``x`` to determine if finite (i.e., not ``NaN`` and not equal to positive or negative infinity). + Tests each element ``x_i`` of the input array ``x`` to determine if finite. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``x_i`` is ``NaN``, the result is ``False``. + - If ``x_i`` is a finite number, the result is ``True``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``False``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. + - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- out: array - an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is finite and ``False`` otherwise. The returned array must have a data type of ``bool``. + an array containing test results. The returned array must have a data type of ``bool``. """ def isinf(x: array, /) -> array: From 31142bbb627fbbcd55ba3ca847a338c33f1102d5 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 12 Dec 2022 11:53:58 -0800 Subject: [PATCH 298/551] Add complex number support to `log1p` (#534) --- .../array_api/elementwise_functions.py | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index c68076aa0..38734f453 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1175,15 +1175,15 @@ def log(x: array, /) -> array: """ def log1p(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, having domain ``[-1, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. .. note:: The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is less than ``-1``, the result is ``NaN``. @@ -1192,15 +1192,41 @@ def log1p(x: array, /) -> array: - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-1`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the evaluated result for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def log2(x: array, /) -> array: From 8062655156069870d6d1d02026bfc781051e22ed Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 08:53:45 -0800 Subject: [PATCH 299/551] Add support for complex number addition (#525) --- .../array_api/array_object.py | 27 ++++++++++++++++--- .../array_api/elementwise_functions.py | 25 ++++++++++++++--- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 600851569..7ed932527 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -144,7 +144,9 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: **Special cases** - For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + Let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + For real-valued floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. @@ -167,12 +169,31 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: .. note:: Floating-point addition is a commutative operation, but not always associative. + For complex floating-point operands, addition is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+------------+------------+----------------+ + | | c | dj | c + dj | + +============+============+============+================+ + | **a** | a + c | a + dj | (a+c) + dj | + +------------+------------+------------+----------------+ + | **bj** | c + bj | (b+d)j | c + (b+d)j | + +------------+------------+------------+----------------+ + | **a + bj** | (a+c) + bj | a + (b+d)j | (a+c) + (b+d)j | + +------------+------------+------------+----------------+ + + For complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. For example, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a`` is ``-0`` and ``c`` is ``-0``, the real component of the result is ``-0``. + - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. + + Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + Parameters ---------- self: array - array instance (augend array). Should have a real-valued data type. + array instance (augend array). Should have a numeric data type. other: Union[int, float, array] - addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 38734f453..34022e2a4 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -161,7 +161,7 @@ def add(x1: array, x2: array, /) -> array: **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. @@ -184,12 +184,31 @@ def add(x1: array, x2: array, /) -> array: .. note:: Floating-point addition is a commutative operation, but not always associative. + For complex floating-point operands, addition is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+------------+------------+----------------+ + | | c | dj | c + dj | + +============+============+============+================+ + | **a** | a + c | a + dj | (a+c) + dj | + +------------+------------+------------+----------------+ + | **bj** | c + bj | (b+d)j | c + (b+d)j | + +------------+------------+------------+----------------+ + | **a + bj** | (a+c) + bj | a + (b+d)j | (a+c) + (b+d)j | + +------------+------------+------------+----------------+ + + For complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. For example, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a`` is ``-0`` and ``c`` is ``-0``, the real component of the result is ``-0``. + - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. + + Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + Parameters ---------- x1: array - first input array. Should have a real-valued data type. + first input array. Should have a numeric data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- From 58580d5f330d97450926384f98c369e724628af5 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 08:55:02 -0800 Subject: [PATCH 300/551] Add support for complex number subtraction (#526) --- spec/API_specification/array_api/array_object.py | 8 +++++--- spec/API_specification/array_api/elementwise_functions.py | 8 +++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 7ed932527..27a151e91 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -947,14 +947,16 @@ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, s def __sub__(self: array, other: Union[int, float, array], /) -> array: """ - Calculates the difference for each element of an array instance with the respective element of the array ``other``. The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). + Calculates the difference for each element of an array instance with the respective element of the array ``other``. + + The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). Parameters ---------- self: array - array instance (minuend array). Should have a real-valued data type. + array instance (minuend array). Should have a numeric data type. other: Union[int, float, array] - subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 34022e2a4..b5812b611 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1826,14 +1826,16 @@ def sqrt(x: array, /) -> array: def subtract(x1: array, x2: array, /) -> array: """ - Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). Parameters ---------- x1: array - first input array. Should have a real-valued data type. + first input array. Should have a numeric data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- From f96cd18b55e14f05b5756ccf527c4bc555a58747 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 08:56:39 -0800 Subject: [PATCH 301/551] Add complex number support to `sum` (#538) --- .../API_specification/array_api/statistical_functions.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/statistical_functions.py b/spec/API_specification/array_api/statistical_functions.py index 9ef10060d..7cd12e106 100644 --- a/spec/API_specification/array_api/statistical_functions.py +++ b/spec/API_specification/array_api/statistical_functions.py @@ -174,21 +174,20 @@ def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtyp - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). - For floating-point operands, - - - If ``x_i`` is ``NaN``, the sum is ``NaN`` (i.e., ``NaN`` values propagate). + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. dtype: Optional[dtype] data type of the returned array. If ``None``, - - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). From 9eca992f0364e720778b9553fecb106b4e928dd3 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 09:06:22 -0800 Subject: [PATCH 302/551] Add complex number support to `abs` (#546) --- .../array_api/array_object.py | 28 ++++++++++++--- .../array_api/elementwise_functions.py | 34 ++++++++++++++++--- 2 files changed, 53 insertions(+), 9 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 27a151e91..384d0286b 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -110,28 +110,48 @@ def T(self: array) -> array: def __abs__(self: array, /) -> array: """ - Calculates the absolute value for each element of an array instance (i.e., the element-wise result has the same magnitude as the respective element but has positive sign). + Calculates the absolute value for each element of an array instance. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. .. note:: For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. **Special cases** - For floating-point operands, let ``self`` equal ``x``. + Let ``self`` equal ``x``. + + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``-0``, the result is ``+0``. - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``. + - If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``. + - If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``. + - If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. note:: + For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. + + .. + TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. + Parameters ---------- self: array - array instance. Should have a real-valued data type. + array instance. Should have a numeric data type. Returns ------- out: array - an array containing the element-wise absolute value. The returned array must have the same data type as ``self``. + an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). .. note:: diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index b5812b611..e16d83fe6 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1,29 +1,53 @@ from ._types import array def abs(x: array, /) -> array: - """ - Calculates the absolute value for each element ``x_i`` of the input array ``x`` (i.e., the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign). + r""" + Calculates the absolute value for each element ``x_i`` of the input array ``x``. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. .. note:: For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + .. note:: + For complex floating-point operands, the complex absolute value is known as the norm, modulus, or magnitude and, for a complex number :math:`z = a + bj` is computed as + + .. math:: + \operatorname{abs}(z) = \sqrt{a^2 + b^2} + **Special Cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``-0``, the result is ``+0``. - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``. + - If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``. + - If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``. + - If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. note:: + For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. + + .. + TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. + Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- out: array - an array containing the absolute value of each element in ``x``. The returned array must have the same data type as ``x``. + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). """ def acos(x: array, /) -> array: From 73a1a9199c3150c400609c1b2ab763f19d335a50 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 09:09:20 -0800 Subject: [PATCH 303/551] Add complex number support to `equal` (#528) --- .../array_api/array_object.py | 24 ++++++++++++++++++- .../array_api/elementwise_functions.py | 22 ++++++++++++++++- spec/design_topics/complex_numbers.rst | 10 ++++++++ spec/design_topics/index.rst | 1 + 4 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 spec/design_topics/complex_numbers.rst diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 384d0286b..bb44f4188 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -369,9 +369,31 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: """ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: - """ + r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. + **Special Cases** + + Let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``False``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` equals ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``False``. + - In the remaining cases, the result is the logical AND of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a == c AND b == d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + Parameters ---------- self: array diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index e16d83fe6..bfd8d03f6 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -812,9 +812,29 @@ def divide(x1: array, x2: array, /) -> array: """ def equal(x1: array, x2: array, /) -> array: - """ + r""" Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``False``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` equals ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``False``. + - In the remaining cases, the result is the logical AND of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a == c AND b == d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + Parameters ---------- x1: array diff --git a/spec/design_topics/complex_numbers.rst b/spec/design_topics/complex_numbers.rst new file mode 100644 index 000000000..1fcba7e81 --- /dev/null +++ b/spec/design_topics/complex_numbers.rst @@ -0,0 +1,10 @@ +.. _complex-numbers: + +Complex Numbers +=============== + +Mathematically, equality comparison between complex numbers depends on the choice of topology. For example, the complex plane has a continuum of infinities; however, when the complex plane is projected onto the surface of a sphere (a stereographic projection commonly referred to as the *Riemann sphere*), infinities coalesce into a single *point at infinity*, thus modeling the extended complex plane. For the former, the value :math:`\infty + 3j` is distinct from (i.e., does not equal) :math:`\infty + 4j`, while, for the latter, :math:`\infty + 3j` does equal :math:`\infty + 4j`. + +Modeling complex numbers as a Riemann sphere conveys certain mathematical niceties (e.g., well-behaved division by zero and preservation of the identity :math:`\frac{1}{\frac{1}{z}} = z`); however, translating the model to IEEE 754 floating-point operations can lead to some unexpected results. For example, according to IEEE 754, :math:`+\infty` and :math:`-\infty` are distinct values; hence, for equality comparison, if :math:`x = +\infty` and :math:`y = -\infty`, then :math:`x \neq y`. In contrast, if we convert :math:`x` and :math:`y` to their complex number equivalents :math:`x = +\infty + 0j` and :math:`y = -\infty + 0j` and then interpret within the context of the extended complex plane, we arrive at the opposite result; namely, :math:`x = y`. + +In short, given the constraints of floating-point arithmetic and the subtleties of signed zeros, infinities, NaNs, and their interaction, crafting a specification which always yields intuitive results and satisfies all use cases involving complex numbers is not possible. Instead, this specification attempts to follow precedent (e.g., C99, Python, Julia, NumPy, and elsewhere), while also minimizing surprise. The result is an imperfect balance in which certain APIs may appear to embrace the one-infinity model found in C/C++ for algebraic operations involving complex numbers (e.g., considering :math:`\infty + \operatorname{NaN}\ j` to be infinite, irrespective of the imaginary component's value, including NaN), while other APIs may rely on the complex plane with its multiplicity of infinities (e.g., in transcendental functions). Accordingly, consumers of this specification should expect that certain results involving complex numbers for one operation may not be wholly consistent with results involving complex numbers for another operation. \ No newline at end of file diff --git a/spec/design_topics/index.rst b/spec/design_topics/index.rst index 55b9d74b4..13e2c8825 100644 --- a/spec/design_topics/index.rst +++ b/spec/design_topics/index.rst @@ -11,6 +11,7 @@ Design topics & constraints device_support static_typing accuracy + complex_numbers branch_cuts complex_number_ordering C_API From f4de3355f924548eb50a63485f92383f88f33de6 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 09:13:18 -0800 Subject: [PATCH 304/551] Add complex number support to `not_equal` (#529) --- .../array_api/array_object.py | 20 +++++++++++++++++++ .../array_api/elementwise_functions.py | 18 +++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index bb44f4188..3a31ce448 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -806,6 +806,26 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. + **Special Cases** + + Let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``True``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` does not equal ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is the logical OR of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a != c OR b != d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + Parameters ---------- self: array diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index bfd8d03f6..ccf7fd7b5 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1504,6 +1504,24 @@ def not_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``True``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` does not equal ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is the logical OR of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a != c OR b != d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + Parameters ---------- x1: array From dbfd0e2bbcecaa2d6958a60c2349707c60e05b4d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 13 Dec 2022 18:50:56 +0100 Subject: [PATCH 305/551] CI: fix build failure due to removed Python version on GitHub Actions (#569) --- .github/workflows/pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index 8709257c1..fc8a97015 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -70,7 +70,7 @@ jobs: - name: 'Install Python' uses: actions/setup-python@v2 with: - python-version: '3.10.2' + python-version: '3.10.9' architecture: 'x64' # Install dependencies: From 770b53b4511646c66abd05b8a8686a930c3af3d7 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:03:19 -0800 Subject: [PATCH 306/551] Add complex number support to APIs for returning unique elements (#540) --- .../array_api/set_functions.py | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/array_api/set_functions.py b/spec/API_specification/array_api/set_functions.py index bd24e5323..34ae41848 100644 --- a/spec/API_specification/array_api/set_functions.py +++ b/spec/API_specification/array_api/set_functions.py @@ -10,15 +10,15 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. .. note:: - Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + Uniqueness 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``, ``nan`` values should be considered distinct. - + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. - Each ``nan`` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. Parameters ---------- @@ -49,12 +49,13 @@ def unique_counts(x: array, /) -> Tuple[array, array]: The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. .. note:: - Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). - Each ``nan`` value should have a count of one, while the counts for signed zeros should be aggregated as a single count. + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. Parameters ---------- @@ -83,9 +84,10 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. .. note:: - Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. @@ -117,9 +119,10 @@ def unique_values(x: array, /) -> array: The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. .. note:: - Uniqueness should be determined based on value equality (i.e., ``x_i == x_j``). For input arrays having floating-point data types, value-based equality implies the following behavior. + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). Parameters From f6c18b5a04c7aa5c5a149963a2e091f09c4bbd74 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:27:16 -0800 Subject: [PATCH 307/551] Add complex number support for `pow` (#537) --- .../array_api/array_object.py | 24 +++++++++++++++---- .../array_api/elementwise_functions.py | 22 +++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 3a31ce448..86bff97af 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -909,17 +909,19 @@ def __pos__(self: array, /) -> array: """ def __pow__(self: array, other: Union[int, float, array], /) -> array: - """ + r""" Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. .. note:: If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - If ``self`` has an integer data type and ``other`` has a real-valued floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. **Special cases** - For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + Let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + For real-valued floating-point operands, - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. @@ -946,12 +948,24 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + For complex floating-point operands, special cases should be handled as if the operation is implemented as ``exp(x2*log(x1))``. + + .. note:: + Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(other*log(self))``, exponentiation has the same branch cut for ``self`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- self: array - array instance whose elements correspond to the exponentiation base. Should have a real-valued data type. + array instance whose elements correspond to the exponentiation base. Should have a numeric data type. other: Union[int, float, array] - other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index ccf7fd7b5..62b336949 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1551,17 +1551,17 @@ def positive(x: array, /) -> array: """ def pow(x1: array, x2: array, /) -> array: - """ + r""" Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. .. note:: If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - If ``x1`` has an integer data type and ``x2`` has a real-valued floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. @@ -1588,12 +1588,24 @@ def pow(x1: array, x2: array, /) -> array: - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + For complex floating-point operands, special cases should be handled as if the operation is implemented as ``exp(x2*log(x1))``. + + .. note:: + Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x1: array - first input array whose elements correspond to the exponentiation base. Should have a real-valued data type. + first input array whose elements correspond to the exponentiation base. Should have a numeric data type. x2: array - second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- From 971c06ae4a4bf107d4198e861c229ca3a71305f8 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:28:22 -0800 Subject: [PATCH 308/551] Add complex number support to `log` (#514) --- .../array_api/elementwise_functions.py | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 62b336949..c29cb8e9d 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1213,12 +1213,12 @@ def less_equal(x1: array, x2: array, /) -> array: """ def log(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm for each element ``x_i`` of the input array ``x``. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is less than ``0``, the result is ``NaN``. @@ -1226,15 +1226,45 @@ def log(x: array, /) -> array: - If ``x_i`` is ``1``, the result is ``+0``. - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-0`` and ``b`` is ``+0``, the result is ``-infinity + πj``. + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. note:: + The natural logarithm of a complex number :math:`z` with polar coordinates :math:`(r,\theta)` equals :math:`\ln r + (\theta + 2n\pi)j` with principal value :math:`\ln r + \theta j`. + + .. note:: + For complex floating-point operands, ``log(conj(x))`` must equal ``conj(log(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def log1p(x: array, /) -> array: From 28e6041f1fd720aa385638e0a95cdc9790918169 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:29:50 -0800 Subject: [PATCH 309/551] Add complex number support to `log10` (#536) --- .../array_api/elementwise_functions.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index c29cb8e9d..df3e265fe 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1348,12 +1348,12 @@ def log2(x: array, /) -> array: """ def log10(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the base ``10`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is less than ``0``, the result is ``NaN``. @@ -1361,15 +1361,25 @@ def log10(x: array, /) -> array: - If ``x_i`` is ``1``, the result is ``+0``. - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. note:: + For complex floating-point operands, ``log10(conj(x))`` must equal ``conj(log10(x))``. + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def logaddexp(x1: array, x2: array, /) -> array: From 0e89b5f281f3f8d54c5601e6b0f68ef973d4a0fa Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:30:15 -0800 Subject: [PATCH 310/551] Add complex number support to `log2` (#535) --- .../array_api/elementwise_functions.py | 20 ++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index df3e265fe..eac8793ad 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1323,12 +1323,12 @@ def log1p(x: array, /) -> array: """ def log2(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the base ``2`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. + r""" + Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is less than ``0``, the result is ``NaN``. @@ -1336,15 +1336,25 @@ def log2(x: array, /) -> array: - If ``x_i`` is ``1``, the result is ``+0``. - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. note:: + For complex floating-point operands, ``log2(conj(x))`` must equal ``conj(log2(x))``. + Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def log10(x: array, /) -> array: From 35cbf3d5c01e308058e83d62d888c89d0e78a1ad Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:31:29 -0800 Subject: [PATCH 311/551] Add complex number support to `linalg.trace` (#541) --- spec/API_specification/array_api/linalg.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index b3595e1fa..619037c0c 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -447,14 +447,12 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). - For floating-point operands, - - - If ``x_i`` is ``NaN``, the sum is ``NaN`` (i.e., ``NaN`` values propagate). + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a numeric data type. offset: int offset specifying the off-diagonal relative to the main diagonal. @@ -466,8 +464,9 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr dtype: Optional[dtype] data type of the returned array. If ``None``, - - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). From 3f1b467be09d058f47cfc8289fcc452effa1fcf3 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:31:59 -0800 Subject: [PATCH 312/551] Add complex number support to `linalg.det` (#542) --- spec/API_specification/array_api/linalg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 619037c0c..50ecdeab4 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -78,7 +78,7 @@ def det(x: array, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. Returns ------- From 7e7f6088697fb5332fa21554777e12fae28912f1 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:36:08 -0800 Subject: [PATCH 313/551] Add complex number support to `sign` (#556) --- .../array_api/elementwise_functions.py | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index eac8793ad..b9dd9f543 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1766,19 +1766,38 @@ def round(x: array, /) -> array: """ def sign(x: array, /) -> array: - """ + r""" Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. + The sign function (also known as the **signum function**) of a number :math:`x_i` is defined as + + .. math:: + \operatorname{sign}(x_i) = \begin{cases} + 0 & \textrm{if } x_i = 0 \\ + \frac{x}{|x|} & \textrm{otherwise} + \end{cases} + + where :math:`|x_i|` is the absolute value of :math:`x_i`. + **Special cases** + For real-valued operands, + - If ``x_i`` is less than ``0``, the result is ``-1``. - If ``x_i`` is either ``-0`` or ``+0``, the result is ``0``. - If ``x_i`` is greater than ``0``, the result is ``+1``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- From e2eb28f092d1a8e2b88f4636c6c291bcc7b2810e Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:37:25 -0800 Subject: [PATCH 314/551] Add complex number support to `linalg.vector_norm` (#550) --- spec/API_specification/array_api/linalg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 50ecdeab4..4d241546f 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -499,7 +499,7 @@ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = No Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. axis: Optional[Union[int, Tuple[int, ...]]] If an integer, ``axis`` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, ``axis`` specifies the axes (dimensions) along which to compute batched vector norms. If ``None``, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: ``None``. keepdims: bool @@ -540,7 +540,7 @@ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = No Returns ------- out: array - an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). """ __all__ = ['cholesky', 'cross', 'det', 'diagonal', 'eigh', 'eigvalsh', 'inv', 'matmul', 'matrix_norm', 'matrix_power', 'matrix_rank', 'matrix_transpose', 'outer', 'pinv', 'qr', 'slogdet', 'solve', 'svd', 'svdvals', 'tensordot', 'trace', 'vecdot', 'vector_norm'] From 775dc7a7630162bafb9d922b0ba9b17317b6351e Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:40:01 -0800 Subject: [PATCH 315/551] Add complex number support for `linalg.inv` (#547) --- spec/API_specification/array_api/linalg.py | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 4d241546f..d4afdd1f4 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -169,18 +169,31 @@ def eigvalsh(x: array, /) -> array: """ def inv(x: array, /) -> array: - """ + r""" Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **inverse matrix** :math:`x^{-1} \in\ \mathbb{K}^{n \times n}` of a square matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x^{-1}x = xx^{-1} = I_n + + where :math:`I_n` is the *n*-dimensional identity matrix. + + The inverse matrix exists if and only if ``x`` is invertible. When ``x`` is invertible, the inverse is unique. + + When ``x`` is a stack of matrices, the function must compute the inverse for each matrix in the stack. + Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. Returns ------- out: array - an array containing the multiplicative inverses. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ def matmul(x1: array, x2: array, /) -> array: From 61694d09e45dccfa0272a512ede82066967d8c16 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:44:32 -0800 Subject: [PATCH 316/551] Add complex number support to `linalg.qr` (#548) --- spec/API_specification/array_api/linalg.py | 34 +++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index d4afdd1f4..c1c0126a0 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -328,16 +328,42 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: """ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tuple[array, array]: - """ - Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where ``Q`` is an orthonormal matrix (or a stack of matrices) and ``R`` is an upper-triangular matrix (or a stack of matrices). + r""" + Returns the QR decomposition of a full column rank matrix (or a stack of matrices). + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **complete QR decomposition** of a matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times m}` is orthogonal when ``x`` is real-valued and unitary when ``x`` is complex-valued and where :math:`R \in\ \mathbb{K}^{m \times n}` is an upper triangular matrix with real diagonal (even when ``x`` is complex-valued). + + When :math:`m \gt n` (tall matrix), as :math:`R` is upper triangular, the last :math:`m - n` rows are zero. In this case, the last :math:`m - n` columns of :math:`Q` can be dropped to form the **reduced QR decomposition**. + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. + + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \qeq m` (wide matrix). + + When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. .. note:: Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. + .. warning:: + The elements in the diagonal of :math:`R` are not necessarily positive. Accordingly, the returned QR decomposition is only unique up to the sign of the diagonal of :math:`R`, and different libraries or inputs on different devices may produce different valid decompositions. + + .. warning:: + The QR decomposition is only well-defined if the first ``k = min(m,n)`` columns of every matrix in ``x`` are linearly independent. + Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a real-valued floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a floating-point data type. mode: Literal['reduced', 'complete'] decomposition mode. Should be one of the following modes: @@ -354,7 +380,7 @@ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tupl - first element must have the field name ``Q`` and must be an array whose shape depends on the value of ``mode`` and contain matrices with orthonormal columns. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, M)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input array ``x``. - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. - Each returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + Each returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def slogdet(x: array, /) -> Tuple[array, array]: From 5283bee1ac28607b8ed0abd7a8663bf3d85d35cc Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 13 Dec 2022 13:45:10 -0800 Subject: [PATCH 317/551] Add complex number support to `linalg.matrix_power` (#549) --- spec/API_specification/array_api/linalg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index c1c0126a0..7396f6efd 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -261,14 +261,14 @@ def matrix_power(x: array, n: int, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. n: int integer exponent. Returns ------- out: array - if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a real-valued floating-point data type determined by :ref:`type-promotion`. + if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. """ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: From 4e82d64710aaacb2aa8de31d1bc2f587e2c9233e Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:04:15 -0800 Subject: [PATCH 318/551] Add complex number support for multiplication (#551) --- .../array_api/array_object.py | 36 ++++++++++++++++--- .../array_api/elementwise_functions.py | 35 +++++++++++++++--- 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 86bff97af..8059051e8 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -764,12 +764,14 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: """ def __mul__(self: array, other: Union[int, float, array], /) -> array: - """ + r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. **Special cases** - For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + Let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + For real-valued floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. @@ -781,6 +783,32 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. - In the remaining cases, where neither ``infinity`` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + For complex floating-point operands, multiplication is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a * c | (a*d)j | (a*c) + (a*d)j | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b*c)j | -(b*d) | -(b*d) + (b*c)j | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a*c) + (b*c)j | -(b*d) + (a*d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), multiplication of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number multiplication + + .. math:: + (a + bj) \cdot (c + dj) = (ac - bd) + (bc + ad)j + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. .. note:: Floating-point multiplication is not always associative due to finite precision. @@ -788,9 +816,9 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Parameters ---------- self: array - array instance. Should have a real-valued data type. + array instance. Should have a numeric data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index b9dd9f543..9b6f0c675 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1496,12 +1496,12 @@ def logical_xor(x1: array, x2: array, /) -> array: """ def multiply(x1: array, x2: array, /) -> array: - """ + r""" Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. @@ -1513,15 +1513,42 @@ def multiply(x1: array, x2: array, /) -> array: - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. - In the remaining cases, where neither ``infinity`` nor ``NaN`` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + For complex floating-point operands, multiplication is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a * c | (a*d)j | (a*c) + (a*d)j | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b*c)j | -(b*d) | -(b*d) + (b*c)j | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a*c) + (b*c)j | -(b*d) + (a*d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), multiplication of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number multiplication + + .. math:: + (a + bj) \cdot (c + dj) = (ac - bd) + (bc + ad)j + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + .. note:: Floating-point multiplication is not always associative due to finite precision. Parameters ---------- x1: array - first input array. Should have a real-valued data type. + first input array. Should have a numeric data type. x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- From 31b3df88d8d4c3c6e92075249fdeda04243174a2 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:05:20 -0800 Subject: [PATCH 319/551] Add support for complex number division (#554) --- .../array_api/array_object.py | 39 ++++++++++++++++--- .../array_api/elementwise_functions.py | 39 ++++++++++++++++--- 2 files changed, 67 insertions(+), 11 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 8059051e8..c58495791 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -1073,7 +1073,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: - """ + r""" Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. .. note:: @@ -1083,7 +1083,9 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: **Special cases** - For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. + Let ``self`` equal ``x1`` and ``other`` equal ``x2``. + + For floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is `NaN`. @@ -1108,17 +1110,44 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + For complex floating-point operands, division is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a / c | -(a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b/c)j | b/d | special rules | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a/c) + (b/c)j | b/d - (a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division + + .. math:: + \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + Parameters ---------- self: array - array instance. Should have a real-valued data type. + array instance. Should have a numeric data type. other: Union[int, float, array] - other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- out: array - an array containing the element-wise results. The returned array should have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. .. note:: diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 9b6f0c675..1d07aa96b 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -763,8 +763,8 @@ def cosh(x: array, /) -> array: """ def divide(x1: array, x2: array, /) -> array: - """ - Calculates the division for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + r""" + Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. .. note:: If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. @@ -773,7 +773,7 @@ def divide(x1: array, x2: array, /) -> array: **Special cases** - For floating-point operands, + For real-valued floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. @@ -798,17 +798,44 @@ def divide(x1: array, x2: array, /) -> array: - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + For complex floating-point operands, division is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a / c | -(a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b/c)j | b/d | special rules | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a/c) + (b/c)j | b/d - (a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division + + .. math:: + \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + Parameters ---------- x1: array - dividend input array. Should have a real-valued data type. + dividend input array. Should have a numeric data type. x2: array - divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns ------- out: array - an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ def equal(x1: array, x2: array, /) -> array: From 91656a71b231502858b13375290c05f014cb08c4 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:07:55 -0800 Subject: [PATCH 320/551] Add complex number support to `prod` (#553) --- .../API_specification/array_api/statistical_functions.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/spec/API_specification/array_api/statistical_functions.py b/spec/API_specification/array_api/statistical_functions.py index 7cd12e106..a49fe4bec 100644 --- a/spec/API_specification/array_api/statistical_functions.py +++ b/spec/API_specification/array_api/statistical_functions.py @@ -101,21 +101,20 @@ def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dty - If ``N`` is ``0``, the product is `1` (i.e., the empty product). - For floating-point operands, - - - If ``x_i`` is ``NaN``, the product is ``NaN`` (i.e., ``NaN`` values propagate). + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. dtype: Optional[dtype] data type of the returned array. If ``None``, - - if the default data type corresponding to the data type "kind" (integer or floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). From 5a6845356bd7c419bf70c25b1aee3d2fbb625584 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:08:33 -0800 Subject: [PATCH 321/551] Add complex number support to `square` (#552) --- .../array_api/elementwise_functions.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 1d07aa96b..b97c13c71 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1955,13 +1955,22 @@ def sinh(x: array, /) -> array: """ def square(x: array, /) -> array: - """ - Squares (``x_i * x_i``) each element ``x_i`` of the input array ``x``. + r""" + Squares each element ``x_i`` of the input array ``x``. + + The square of a number ``x_i`` is defined as + + .. math:: + x_i^2 = x_i \cdot x_i + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). Parameters ---------- x: array - input array. Should have a real-valued data type. + input array. Should have a numeric data type. Returns ------- From 031987dd425af71e3ae20c0b408da9df49f2ecc3 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:14:47 -0800 Subject: [PATCH 322/551] Add complex number support to `matmul` (#557) --- spec/API_specification/array_api/array_object.py | 8 ++++++-- .../array_api/linear_algebra_functions.py | 8 ++++++-- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index c58495791..b325e0010 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -682,9 +682,13 @@ def __matmul__(self: array, other: array, /) -> array: Parameters ---------- self: array - array instance. Should have a real-valued data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + array instance. Should have a numeric data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. other: array - other array. Should have a real-valued data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + other array. Should have a numeric data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. Returns ------- diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py index f8f15e5b0..96a44505a 100644 --- a/spec/API_specification/array_api/linear_algebra_functions.py +++ b/spec/API_specification/array_api/linear_algebra_functions.py @@ -10,9 +10,13 @@ def matmul(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first input array. Should have a real-valued data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + first input array. Should have a numeric data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. x2: array - second input array. Should have a real-valued data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + second input array. Should have a numeric data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. Returns ------- From 8f4327c14699f897f0751013bacb037df90698a5 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:18:22 -0800 Subject: [PATCH 323/551] Add complex number support to `tensordot` (#558) --- .../array_api/linear_algebra_functions.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py index 96a44505a..811916d60 100644 --- a/spec/API_specification/array_api/linear_algebra_functions.py +++ b/spec/API_specification/array_api/linear_algebra_functions.py @@ -60,12 +60,15 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], """ Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. + .. note:: + The ``tensordot`` function corresponds to the generalized matrix product. + Parameters ---------- x1: array - first input array. Should have a real-valued data type. + first input array. Should have a numeric data type. x2: array - second input array. Should have a real-valued data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + second input array. Should have a numeric data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. .. note:: Contracted axes (dimensions) must not be broadcasted. @@ -81,6 +84,10 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the generalized matrix product. + Returns ------- out: array From 8cf015ee6e9c3e466a535c379311790f8b28ae6a Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:19:29 -0800 Subject: [PATCH 324/551] Add complex number support to `linalg.outer` (#560) --- spec/API_specification/array_api/linalg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 7396f6efd..d455322dc 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -300,9 +300,9 @@ def outer(x1: array, x2: array, /) -> array: Parameters ---------- x1: array - first one-dimensional input array of size ``N``. Should have a real-valued data type. + first one-dimensional input array of size ``N``. Must have a numeric data type. x2: array - second one-dimensional input array of size ``M``. Should have a real-valued data type. + second one-dimensional input array of size ``M``. Must have a numeric data type. Returns ------- From e9a16835c1997c0677c14433604611eb5727017a Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:19:55 -0800 Subject: [PATCH 325/551] Add complex number support to `linalg.cross` (#559) --- spec/API_specification/array_api/linalg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index d455322dc..23bb5ab91 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -48,9 +48,9 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: Parameters ---------- x1: array - first input array. Should have a real-valued data type. + first input array. Must have a numeric data type. x2: array - second input array. Must be compatible with ``x1`` for all non-compute axes (see :ref:`broadcasting`). The size of the axis over which to compute the cross product must be the same size as the respective axis in ``x1``. Should have a real-valued data type. + second input array. Must be compatible with ``x1`` for all non-compute axes (see :ref:`broadcasting`). The size of the axis over which to compute the cross product must be the same size as the respective axis in ``x1``. Must have a numeric data type. .. note:: The compute axis (dimension) must not be broadcasted. From a1304fef1f5580801167edfaeaae48194c349d41 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:20:51 -0800 Subject: [PATCH 326/551] Add complex number support to `linalg.svdvals` (#562) --- spec/API_specification/array_api/linalg.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 23bb5ab91..b27e26cdc 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -460,15 +460,17 @@ def svdvals(x: array, /) -> array: """ Returns the singular values of a matrix (or a stack of matrices) ``x``. + When ``x`` is a stack of matrices, the function must compute the singular values for each matrix in the stack. + Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a real-valued floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. Returns ------- out: array - an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have the same real-valued floating-point data type as ``x``. + an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). """ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: From 3debcf1c3c8b8ac8ccae34262284cdf7c55ba08b Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:21:48 -0800 Subject: [PATCH 327/551] Add complex number support to `linalg.matrix_rank` (#563) --- spec/API_specification/array_api/linalg.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index b27e26cdc..96d311ee8 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -275,10 +275,12 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a """ Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). + When ``x`` is a stack of matrices, the function must compute the number of non-zero singular values for each matrix in the stack. + Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. rtol: Optional[Union[float, array]] relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. From 32de3956fc131bcb607dc4addc6dfac03fa4a77e Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:22:31 -0800 Subject: [PATCH 328/551] Add complex number support to `linalg.matrix_norm` (#565) --- spec/API_specification/array_api/linalg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 96d311ee8..29a1f1c90 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -208,7 +208,7 @@ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. keepdims: bool If ``True``, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the last two axes (dimensions) must not be included in the result. Default: ``False``. ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] @@ -251,7 +251,7 @@ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, Returns ------- out: array - an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). """ def matrix_power(x: array, n: int, /) -> array: From 35baedc4db7e3f5cea4afff41efdfd32edc283bd Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:26:40 -0800 Subject: [PATCH 329/551] Add complex number support to `linalg.solve` (#566) --- spec/API_specification/array_api/linalg.py | 23 ++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 29a1f1c90..12bd54792 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -414,23 +414,34 @@ def slogdet(x: array, /) -> Tuple[array, array]: """ def solve(x1: array, x2: array, /) -> array: - """ - Returns the solution to the system of linear equations represented by the well-determined (i.e., full rank) linear matrix equation ``AX = B``. + r""" + Returns the solution of a square system of linear equations with a unique solution. + + Let ``x1`` equal :math:`A` and ``x2`` equal :math:`B`. If the promoted data type of ``x1`` and ``x2`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if the promoted data type of ``x1`` and ``x2`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + This function computes the solution :math:`X \in\ \mathbb{K}^{m \times k}` of the **linear system** associated to :math:`A \in\ \mathbb{K}^{m \times m}` and :math:`B \in\ \mathbb{K}^{m \times k}` and is defined as + + .. math:: + AX = B + + This system of linear equations has a unique solution if and only if :math:`A` is invertible. .. note:: - Whether an array library explicitly checks whether an input array is full rank is implementation-defined. + Whether an array library explicitly checks whether ``x1`` is invertible is implementation-defined. + + When ``x1`` and/or ``x2`` is a stack of matrices, the function must compute a solution for each matrix in the stack. Parameters ---------- x1: array - coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a real-valued floating-point data type. + coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. """ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: From dff1997a5b4c455fb5b7be731780ce409d6e9a7d Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:33:11 -0800 Subject: [PATCH 330/551] Add complex number support to `linspace` (#568) --- .../array_api/creation_functions.py | 37 +++++++++++++++---- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index 830337905..593b00150 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -213,24 +213,45 @@ def full_like(x: array, /, fill_value: Union[bool, int, float, complex], *, dtyp an array having the same shape as ``x`` and where every element is equal to ``fill_value``. """ -def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, dtype: Optional[dtype] = None, device: Optional[device] = None, endpoint: bool = True) -> array: - """ +def linspace(start: Union[int, float, complex], stop: Union[int, float, complex], /, num: int, *, dtype: Optional[dtype] = None, device: Optional[device] = None, endpoint: bool = True) -> array: + r""" Returns evenly spaced numbers over a specified interval. + Let :math:`N` be the number of generated values (which is either ``num`` or ``num+1`` depending on whether ``endpoint`` is ``True`` or ``False``, respectively). For real-valued output arrays, the spacing between values is given by + + .. math:: + \Delta_{\textrm{real}} = \frac{\textrm{stop} - \textrm{start}}{N - 1} + + For complex output arrays, let ``a = real(start)``, ``b = imag(start)``, ``c = real(stop)``, and ``d = imag(stop)``. The spacing between complex values is given by + + .. math:: + \Delta_{\textrm{complex}} = \frac{c-a}{N-1} + \frac{d-b}{N-1} j + Parameters ---------- - start: Union[int, float] + start: Union[int, float, complex] the start of the interval. - stop: Union[int, float] + stop: Union[int, float, complex] the end of the interval. If ``endpoint`` is ``False``, the function must generate a sequence of ``num+1`` evenly spaced numbers starting with ``start`` and ending with ``stop`` and exclude the ``stop`` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval ``[start, stop)``. If ``endpoint`` is ``True``, the output array must consist of evenly spaced numbers over the closed interval ``[start, stop]``. Default: ``True``. .. note:: The step size changes when `endpoint` is `False`. num: int - number of samples. Must be a non-negative integer value; otherwise, the function must raise an exception. + number of samples. Must be a nonnegative integer value. dtype: Optional[dtype] - output array data type. Should be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, + + - if either ``start`` or ``stop`` is a ``complex`` number, the output data type must be the default complex floating-point data type. + - if both ``start`` and ``stop`` are real-valued, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, conversion of ``start`` and ``stop`` should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. + device: Optional[device] device on which to place the created array. Default: ``None``. endpoint: bool @@ -243,10 +264,10 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, .. note:: - While this specification recommends that this function only return arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. .. note:: - As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output real-valued floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. """ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: From a1d7edc35858eec7d435f43c9b56c87f02b36af6 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:46:13 -0800 Subject: [PATCH 331/551] Add complex number support to `linalg.slogdet` (#567) --- spec/API_specification/array_api/linalg.py | 40 ++++++++++++++++------ 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 12bd54792..b61cb8395 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -386,31 +386,51 @@ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tupl """ def slogdet(x: array, /) -> Tuple[array, array]: - """ + r""" Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. .. note:: The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling ``det`` may overflow or underflow. + The sign of the determinant is given by + + .. math:: + \operatorname{sign}(\det x) = \begin{cases} + 0 & \textrm{if } \det x = 0 \\ + \frac{\det x}{|\det x|} & \textrm{otherwise} + \end{cases} + + where :math:`|\det x|` is the absolute value of the determinant of ``x``. + + When ``x`` is a stack of matrices, the function must compute the sign and natural logarithm of the absolute value of the determinant for each matrix in the stack. + + **Special Cases** + + For real-valued floating-point operands, + + - If the determinant is zero, the ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``. + + For complex floating-point operands, + + - If the determinant is ``0 + 0j``, the ``sign`` should be ``0 + 0j`` and ``logabsdet`` should be ``-infinity + 0j``. + + .. note:: + Depending on the underlying algorithm, when the determinant is zero, the returned result may differ from ``-infinity`` (or ``-infinity + 0j``). In all cases, the determinant should be equal to ``sign * exp(logabsdet)`` (although, again, the result may be subject to numerical precision errors). + Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. Returns ------- out: Tuple[array, array] a namedtuple (``sign``, ``logabsdet``) whose - - first element must have the field name ``sign`` and must be an array containing a number representing the sign of the determinant for each square matrix. - - second element must have the field name ``logabsdet`` and must be an array containing the determinant for each square matrix. - - For a real matrix, the sign of the determinant must be either ``1``, ``0``, or ``-1``. + - first element must have the field name ``sign`` and must be an array containing a number representing the sign of the determinant for each square matrix. Must have the same data type as ``x``. + - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). - Each returned array must have shape ``shape(x)[:-2]`` and a real-valued floating-point data type determined by :ref:`type-promotion`. - - .. note:: - If a determinant is zero, then the corresponding ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to ``sign * exp(logsabsdet)`` (although, again, the result may be subject to numerical precision errors). + Each returned array must have shape ``shape(x)[:-2]``. """ def solve(x1: array, x2: array, /) -> array: From fdfa5bd29fcaeec418a4860b3d27f8fd0daa737c Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 11:58:49 -0800 Subject: [PATCH 332/551] Add complex number support to `linalg.svd` (#561) --- spec/API_specification/array_api/linalg.py | 43 +++++++++++++++++----- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index b61cb8395..9344875a9 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -465,28 +465,51 @@ def solve(x1: array, x2: array, /) -> array: """ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: - """ - Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) ``x``, where ``U`` is a matrix (or a stack of matrices) with orthonormal columns, ``S`` is a vector of non-negative numbers (or stack of vectors), and ``Vh`` is a matrix (or a stack of matrices) with orthonormal rows. + r""" + Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The full **singular value decomposition** of an :math:`m \times n` matrix :math:`x \in\ \mathbb{K}^{m \times n}` is a factorization of the form + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times m}`, :math:`\Sigma \in\ \mathbb{K}^{m \times\ n}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}` with :math:`k = \operatorname{min}(m, n)`, :math:`V^H \in\ \mathbb{K}^{n \times n}`, and where :math:`V^H` is the conjugate transpose when :math:`V` is complex and the transpose when :math:`V` is real-valued. When ``x`` is real-valued, :math:`U`, :math:`V` (and thus :math:`V^H`) are orthogonal, and, when ``x`` is complex, :math:`U`, :math:`V` (and thus :math:`V^H`) are unitary. + + When :math:`m \gt n` (tall matrix), we can drop the last :math:`m - n` columns of :math:`U` to form the reduced SVD + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times k}`, :math:`\Sigma \in\ \mathbb{K}^{k \times\ k}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}`, and :math:`V^H \in\ \mathbb{K}^{k \times n}`. In this case, :math:`U` and :math:`V` have orthonormal columns. + + Similarly, when :math:`n \gt m` (wide matrix), we can drop the last :math:`n - m` columns of :math:`V` to also form a reduced SVD. + + This function returns the decomposition :math:`U`, :math:`S`, and :math:`V^H`, where :math:`S = \operatorname{diag}(\Sigma)`. + + When ``x`` is a stack of matrices, the function must compute the singular value decomposition for each matrix in the stack. + + .. warning:: + The returned arrays :math:`U` and :math:`V` are neither unique nor continuous with respect to ``x``. Because :math:`U` and :math:`V` are not unique, different hardware and software may compute different singular vectors. + + Non-uniqueness stems from the fact that multiplying any pair of singular vectors :math:`u_k`, :math:`v_k` by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another two valid singular vectors of the matrix. Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a real-valued floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. full_matrices: bool If ``True``, compute full-sized ``U`` and ``Vh``, such that ``U`` has shape ``(..., M, M)`` and ``Vh`` has shape ``(..., N, N)``. If ``False``, compute on the leading ``K`` singular vectors, such that ``U`` has shape ``(..., M, K)`` and ``Vh`` has shape ``(..., K, N)`` and where ``K = min(M, N)``. Default: ``True``. Returns ------- - .. - NOTE: once complex numbers are supported, each square matrix must be Hermitian. out: Union[array, Tuple[array, ...]] a namedtuple ``(U, S, Vh)`` whose - - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. - - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. - - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. - - Each returned array must have the same real-valued floating-point data type as ``x``. + - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). + - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. """ def svdvals(x: array, /) -> array: From 7d9752f303195013a7eb99f33c46ad711070d0c7 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 12:01:26 -0800 Subject: [PATCH 333/551] Add complex number support to `linalg.pinv` (#564) --- spec/API_specification/array_api/linalg.py | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 9344875a9..1d6faf631 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -313,20 +313,36 @@ def outer(x1: array, x2: array, /) -> array: """ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: - """ + r""" Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. + The pseudo-inverse of a matrix :math:`A`, denoted :math:`A^{+}`, is defined as the matrix that "solves" the least-squares problem :math:`Ax = b` (i.e., if :math:`\overline{x}` is a solution, then :math:`A^{+}` is the matrix such that :math:`\overline{x} = A^{+}b`). + + While the pseudo-inverse can be defined algebraically, one can understand the pseudo-inverse via singular value decomposition (SVD). Namely, if + + .. math:: + A = U \Sigma V^H + + is a singular decomposition of :math:`A`, then + + .. math:: + A^{+} = U \Sigma^{+} V^H + + where :math:`U` and :math:`V^H` are orthogonal matrices, :math:`\Sigma` is a diagonal matrix consisting of :math:`A`'s singular values, and :math:`\Sigma^{+}` is then a diagonal matrix consisting of the reciprocals of :math:`A`'s singular values, leaving zeros in place. During numerical computation, only elements larger than a small tolerance are considered nonzero, and all others replaced by zeros. + + When ``x`` is a stack of matrices, the function must compute the pseudo-inverse for each matrix in the stack. + Parameters ---------- x: array - input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a real-valued floating-point data type. + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. rtol: Optional[Union[float, array]] relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. Returns ------- out: array - an array containing the pseudo-inverses. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). """ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tuple[array, array]: From adca8ce023471a8c9018cc55bab0ad5bfd6905d8 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 14 Dec 2022 20:06:18 +0000 Subject: [PATCH 334/551] Align casting methods with Python behaviour (#497) * Introduce conservative `x.__complex__()` * Don't hard require same-kind arrays for builtin cast methods * Align casting methods with Python behaviour * Remove unnecessary `__int__` note on out-of-scope beyond bounds * `__index__`: leave bool arrays unspecified and restrict out to `int` * Update `__complex__` note with complex results * Clarify `__bool__` note language * "real-valued" -> "numeric" input array in `__bool__` note * Clearer and spec-consistent language for casting methods Co-authored-by: Athan * Special case neg zeros in `x.__int__()` * Special cases over note in `x.__bool__()` * Special cases over notes for boolean cross-kind casting * Add missing backticks * Update copy * Add special cases for real-valued floating-point operands Co-authored-by: Athan --- .../array_api/array_object.py | 83 +++++++++++++++++-- spec/API_specification/array_object.rst | 1 + 2 files changed, 77 insertions(+), 7 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index b325e0010..f7cb3e133 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -265,12 +265,22 @@ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> def __bool__(self: array, /) -> bool: """ - Converts a zero-dimensional boolean array to a Python ``bool`` object. + Converts a zero-dimensional array to a Python ``bool`` object. + + **Special cases** + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``True``. + - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. Parameters ---------- self: array - zero-dimensional array instance. Must have a boolean data type. + zero-dimensional array instance. Returns ------- @@ -278,6 +288,35 @@ def __bool__(self: array, /) -> bool: a Python ``bool`` object representing the single element of the array. """ + def __complex__(self: array, /) -> complex: + """ + Converts a zero-dimensional array to a Python ``complex`` object. + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1+0j``. + - If ``self`` is ``False``, the result is ``0+0j``. + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. + - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. + - If ``self`` is a finite number, the result is ``self + 0j``. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: complex + a Python ``complex`` object representing the single element of the array instance. + """ + def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -413,12 +452,22 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: def __float__(self: array, /) -> float: """ - Converts a zero-dimensional floating-point array to a Python ``float`` object. + Converts a zero-dimensional array to a Python ``float`` object. + + .. note:: + Casting integer values outside the representable bounds of Python's float type is not specified and is implementation-dependent. + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. Parameters ---------- self: array - zero-dimensional array instance. Must have a real-valued floating-point data type. + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. Returns ------- @@ -561,7 +610,7 @@ def __index__(self: array, /) -> int: Parameters ---------- self: array - zero-dimensional array instance. Must have an integer data type. + zero-dimensional array instance. Should have an integer data type. If ``self`` has a floating-point data type, the function must raise a ``TypeError``. Returns ------- @@ -571,17 +620,37 @@ def __index__(self: array, /) -> int: def __int__(self: array, /) -> int: """ - Converts a zero-dimensional integer array to a Python ``int`` object. + Converts a zero-dimensional array to a Python ``int`` object. + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + For floating-point operands, + + - If ``self`` is a finite number, the result is the integer part of ``self``. + - If ``self`` is ``-0``, the result is ``0``. Parameters ---------- self: array - zero-dimensional array instance. Must have an integer data type. + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. Returns ------- out: int a Python ``int`` object representing the single element of the array instance. + + + **Raises** + + For floating-point operands, + + - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. + - If ``self`` is ``NaN``, raise ``ValueError``. """ def __invert__(self: array, /) -> array: diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index 758e08582..b45e41987 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -283,6 +283,7 @@ Methods array.__and__ array.__array_namespace__ array.__bool__ + array.__complex__ array.__dlpack__ array.__dlpack_device__ array.__eq__ From b3f28299e4ca291ab7690727ce4d6670fba1a235 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 12:34:23 -0800 Subject: [PATCH 335/551] Add complex number support to `eigh` and `eigvalsh` (#543) --- spec/API_specification/array_api/linalg.py | 61 +++++++++++++++------- 1 file changed, 42 insertions(+), 19 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 1d6faf631..c56eb9bbb 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -110,59 +110,82 @@ def diagonal(x: array, /, *, offset: int = 0) -> array: """ def eigh(x: array, /) -> Tuple[array]: - """ - Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) ``x``, where ``Q`` is an orthogonal matrix (or a stack of matrices) and ``L`` is a vector (or a stack of vectors). + r""" + Returns an eigenvalue decomposition of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalue decomposition** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = Q \Lambda Q^H + + with :math:`Q \in \mathbb{K}^{n \times n}` and :math:`\Lambda \in \mathbb{R}^n` and where :math:`Q^H` is the conjugate transpose when :math:`Q` is complex and the transpose when :math:`Q` is real-valued and :math:`\Lambda` is a diagonal matrix whose diagonal elements are the corresponding eigenvalues. When ``x`` is real-valued, :math:`Q` is orthogonal, and, when ``x`` is complex, :math:`Q` is unitary. .. note:: - The function ``eig`` will be added in a future version of the specification, as it requires complex number support. + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. warning:: + The eigenvectors of a symmetric matrix are not unique and are not continuous with respect to ``x``. Because eigenvectors are not unique, different hardware and software may compute different eigenvectors. + + Non-uniqueness stems from the fact that multiplying an eigenvector by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another set of valid eigenvectors. - .. - NOTE: once complex numbers are supported, each square matrix must be Hermitian. + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. .. note:: - Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. + The function ``eig`` will be added in a future version of the specification. Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a real-valued floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. Returns ------- out: Tuple[array] a namedtuple (``eigenvalues``, ``eigenvectors``) whose - - first element must have the field name ``eigenvalues`` (corresponding to ``L`` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)``. - - second element have have the field name ``eigenvectors`` (corresponding to ``Q`` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)``. + - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). + - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. - Each returned array must have the same real-valued floating-point data type as ``x``. .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. """ def eigvalsh(x: array, /) -> array: - """ - Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) ``x``. + r""" + Returns the eigenvalues of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. - .. note:: - The function ``eigvals`` will be added in a future version of the specification, as it requires complex number support. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalues** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` are defined as the roots (counted with multiplicity) of the polynomial :math:`p` of degree :math:`n` given by - .. - NOTE: once complex numbers are supported, each square matrix must be Hermitian. + .. math:: + p(\lambda) = \operatorname{det}(x - \lambda I_n) + + where :math:`\lambda \in \mathbb{R}` and where :math:`I_n` is the *n*-dimensional identity matrix. + + .. note:; + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. .. note:: - Whether an array library explicitly checks whether an input array is a symmetric matrix (or a stack of symmetric matrices) is implementation-defined. + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eigvals`` will be added in a future version of the specification. Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a real-valued floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. Returns ------- out: array - an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have the same data type as ``x``. + an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. From 7eee20d964353d854c67030340a3cbe79e3df538 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 14 Dec 2022 21:49:00 +0100 Subject: [PATCH 336/551] Add complex number support to `vecdot` (#512) * Add complex number support to `vecdot` Closes gh-356 (where the definition x1^H x2 was decided). * Move operation description to extended intro * Fix equation * Update equation * Update copy * Fix equation * Fix equation * Remove note * Add linebreak * Update copy Co-authored-by: Athan --- .../array_api/linear_algebra_functions.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py index 811916d60..6507c37cd 100644 --- a/spec/API_specification/array_api/linear_algebra_functions.py +++ b/spec/API_specification/array_api/linear_algebra_functions.py @@ -97,13 +97,20 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Computes the (vector) dot product of two arrays. + + Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as + + .. math:: + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} a_i\overline{b_i} + + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{b_i}` denotes the complex conjugate if :math:`b_i` is complex and the identity if :math:`b_i` is real-valued. Parameters ---------- x1: array - first input array. Should have a real-valued data type. + first input array. Should have a floating-point data type. x2: array - second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). The size of the axis over which to compute the dot product must be the same size as the respective axis in ``x1``. Should have a real-valued data type. + second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). The size of the axis over which to compute the dot product must be the same size as the respective axis in ``x1``. Should have a floating-point data type. .. note:: The contracted axis (dimension) must not be broadcasted. From d56d369bb7bb44472428404bb079d35952b8ec4d Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Dec 2022 13:05:40 -0800 Subject: [PATCH 337/551] Update dtype guidance for `eigh` and `eigvalsh` (#572) --- spec/API_specification/array_api/linalg.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index c56eb9bbb..faa8ba9e6 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -139,7 +139,7 @@ def eigh(x: array, /) -> Tuple[array]: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. Returns ------- @@ -179,7 +179,7 @@ def eigvalsh(x: array, /) -> array: Parameters ---------- x: array - input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must have a floating-point data type. + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. Returns ------- From 162034b12711dad54589c5dc9e75942695a7957f Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 14 Dec 2022 22:59:49 +0100 Subject: [PATCH 338/551] Run `black` on the `.py` files for the API specification --- spec/API_specification/array_api/_types.py | 59 +++++-- .../array_api/array_object.py | 65 ++++++-- spec/API_specification/array_api/constants.py | 6 +- .../array_api/creation_functions.py | 151 +++++++++++++++--- .../array_api/data_type_functions.py | 15 +- .../API_specification/array_api/data_types.py | 4 +- .../array_api/elementwise_functions.py | 151 ++++++++++++++++-- spec/API_specification/array_api/fft.py | 107 +++++++++++-- .../array_api/indexing_functions.py | 4 +- spec/API_specification/array_api/linalg.py | 79 ++++++++- .../array_api/linear_algebra_functions.py | 21 ++- .../array_api/manipulation_functions.py | 40 ++++- .../array_api/searching_functions.py | 7 +- .../array_api/set_functions.py | 7 +- .../array_api/sorting_functions.py | 13 +- .../array_api/statistical_functions.py | 70 +++++++- .../array_api/utility_functions.py | 21 ++- 17 files changed, 705 insertions(+), 115 deletions(-) diff --git a/spec/API_specification/array_api/_types.py b/spec/API_specification/array_api/_types.py index b55e8fb25..be81b40ae 100644 --- a/spec/API_specification/array_api/_types.py +++ b/spec/API_specification/array_api/_types.py @@ -7,18 +7,29 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Any, List, Literal, Optional, Sequence, Tuple, TypeVar, Union, Protocol +from typing import ( + Any, + List, + Literal, + Optional, + Sequence, + Tuple, + TypeVar, + Union, + Protocol, +) from enum import Enum -array = TypeVar('array') -device = TypeVar('device') -dtype = TypeVar('dtype') -SupportsDLPack = TypeVar('SupportsDLPack') -SupportsBufferProtocol = TypeVar('SupportsBufferProtocol') -PyCapsule = TypeVar('PyCapsule') +array = TypeVar("array") +device = TypeVar("device") +dtype = TypeVar("dtype") +SupportsDLPack = TypeVar("SupportsDLPack") +SupportsBufferProtocol = TypeVar("SupportsBufferProtocol") +PyCapsule = TypeVar("PyCapsule") # ellipsis cannot actually be imported from anywhere, so include a dummy here # to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 -ellipsis = TypeVar('ellipsis') +ellipsis = TypeVar("ellipsis") + @dataclass class finfo_object: @@ -28,6 +39,7 @@ class finfo_object: min: float smallest_normal: float + @dataclass class iinfo_object: bits: int @@ -37,11 +49,32 @@ class iinfo_object: _T_co = TypeVar("_T_co", covariant=True) + class NestedSequence(Protocol[_T_co]): - def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: ... - def __len__(self, /) -> int: ... + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: + ... + + def __len__(self, /) -> int: + ... -__all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', -'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', 'Sequence', -'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object', 'Enum'] +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", +] diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index f7cb3e133..3dee8c5ab 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -1,9 +1,20 @@ from __future__ import annotations -from ._types import (array, dtype as Dtype, device as Device, Optional, Tuple, - Union, Any, PyCapsule, Enum, ellipsis) - -class _array(): +from ._types import ( + array, + dtype as Dtype, + device as Device, + Optional, + Tuple, + Union, + Any, + PyCapsule, + Enum, + ellipsis, +) + + +class _array: def __init__(self: array) -> None: """ Initialize the attributes for the array object class. @@ -246,7 +257,9 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ - def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: + def __array_namespace__( + self: array, /, *, api_version: Optional[str] = None + ) -> Any: """ Returns an object that has all the array API functions on it. @@ -298,9 +311,9 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``True``, the result is ``1+0j``. - If ``self`` is ``False``, the result is ``0+0j``. - + For real-valued floating-point operands, - + - If ``self`` is ``NaN``, the result is ``NaN + NaN j``. - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. @@ -317,7 +330,9 @@ def __complex__(self: array, /) -> complex: a Python ``complex`` object representing the single element of the array instance. """ - def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: + def __dlpack__( + self: array, /, *, stream: Optional[Union[int, Any]] = None + ) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -559,7 +574,13 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. """ - def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: + def __getitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + /, + ) -> array: """ Returns ``self[key]``. @@ -1099,7 +1120,14 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ - def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: + def __setitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + value: Union[int, float, bool, array], + /, + ) -> None: """ Sets ``self[key]`` to ``value``. @@ -1196,17 +1224,17 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: +------------+----------------+-----------------+--------------------------+ In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. - + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division - + .. math:: \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} - + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, - + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. - In the remaining cases, the result is implementation dependent. - + .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. @@ -1248,7 +1276,9 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ - def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: + def to_device( + self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None + ) -> array: """ Copy the array from the device on which it currently resides to the specified ``device``. @@ -1271,6 +1301,7 @@ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. """ + array = _array -__all__ = ['array'] +__all__ = ["array"] diff --git a/spec/API_specification/array_api/constants.py b/spec/API_specification/array_api/constants.py index 18c8ac761..c7aaddc5e 100644 --- a/spec/API_specification/array_api/constants.py +++ b/spec/API_specification/array_api/constants.py @@ -5,12 +5,12 @@ ``e = 2.71828182845904523536028747135266249775724709369995...`` """ -inf = float('inf') +inf = float("inf") """ IEEE 754 floating-point representation of (positive) infinity. """ -nan = float('nan') +nan = float("nan") """ IEEE 754 floating-point representation of Not a Number (``NaN``). """ @@ -27,4 +27,4 @@ ``pi = 3.1415926535897932384626433...`` """ -__all__ = ['e', 'inf', 'nan', 'newaxis', 'pi'] +__all__ = ["e", "inf", "nan", "newaxis", "pi"] diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index 593b00150..bfb89b2ba 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -1,7 +1,25 @@ -from ._types import (List, NestedSequence, Optional, SupportsBufferProtocol, Tuple, Union, array, - device, dtype) - -def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None, step: Union[int, float] = 1, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: +from ._types import ( + List, + NestedSequence, + Optional, + SupportsBufferProtocol, + Tuple, + Union, + array, + device, + dtype, +) + + +def arange( + start: Union[int, float], + /, + stop: Optional[Union[int, float]] = None, + step: Union[int, float] = 1, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. @@ -28,7 +46,17 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. """ -def asarray(obj: Union[array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: + +def asarray( + obj: Union[ + array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol + ], + /, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: r""" Convert the input to an array. @@ -71,7 +99,13 @@ def asarray(obj: Union[array, bool, int, float, complex, NestedSequence, Support an array containing the data from ``obj``. """ -def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def empty( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns an uninitialized array having a specified `shape`. @@ -90,7 +124,10 @@ def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, an array containing uninitialized data. """ -def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def empty_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns an uninitialized array with the same ``shape`` as an input array ``x``. @@ -109,12 +146,21 @@ def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d an array having the same shape as ``x`` and containing uninitialized data. """ -def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def eye( + n_rows: int, + n_cols: Optional[int] = None, + /, + *, + k: int = 0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. .. note:: - An output array having a complex floating-point data type must have the value ``1 + 0j`` along the ``k``\th diagonal and ``0 + 0j`` elsewhere. + An output array having a complex floating-point data type must have the value ``1 + 0j`` along the ``k``\th diagonal and ``0 + 0j`` elsewhere. Parameters ---------- @@ -135,6 +181,7 @@ def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Opti an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. """ + def from_dlpack(x: object, /) -> array: """ Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. @@ -155,7 +202,14 @@ def from_dlpack(x: object, /) -> array: The returned array may be either a copy or a view. See :ref:`data-interchange` for details. """ -def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[bool, int, float, complex], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def full( + shape: Union[int, Tuple[int, ...]], + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with ``fill_value``. @@ -185,7 +239,15 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[bool, int, float, an array where every element is equal to ``fill_value``. """ -def full_like(x: array, /, fill_value: Union[bool, int, float, complex], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def full_like( + x: array, + /, + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. @@ -213,7 +275,17 @@ def full_like(x: array, /, fill_value: Union[bool, int, float, complex], *, dtyp an array having the same shape as ``x`` and where every element is equal to ``fill_value``. """ -def linspace(start: Union[int, float, complex], stop: Union[int, float, complex], /, num: int, *, dtype: Optional[dtype] = None, device: Optional[device] = None, endpoint: bool = True) -> array: + +def linspace( + start: Union[int, float, complex], + stop: Union[int, float, complex], + /, + num: int, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + endpoint: bool = True, +) -> array: r""" Returns evenly spaced numbers over a specified interval. @@ -270,7 +342,8 @@ def linspace(start: Union[int, float, complex], stop: Union[int, float, complex] As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. """ -def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: + +def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -296,12 +369,18 @@ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: Each returned array should have the same data type as the input arrays. """ -def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def ones( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with ones. .. note:: - An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). Parameters ---------- @@ -318,12 +397,15 @@ def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, d an array containing ones. """ -def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def ones_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. .. note:: - An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). Parameters ---------- @@ -340,6 +422,7 @@ def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[de an array having the same shape as ``x`` and filled with ones. """ + def tril(x: array, /, *, k: int = 0) -> array: """ Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. @@ -363,6 +446,7 @@ def tril(x: array, /, *, k: int = 0) -> array: an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. """ + def triu(x: array, /, *, k: int = 0) -> array: """ Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. @@ -386,7 +470,13 @@ def triu(x: array, /, *, k: int = 0) -> array: an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. """ -def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def zeros( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with zeros. @@ -405,7 +495,10 @@ def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, an array containing zeros. """ -def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def zeros_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. @@ -424,4 +517,22 @@ def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d an array having the same shape as ``x`` and filled with zeros. """ -__all__ = ['arange', 'asarray', 'empty', 'empty_like', 'eye', 'from_dlpack', 'full', 'full_like', 'linspace', 'meshgrid', 'ones', 'ones_like', 'tril', 'triu', 'zeros', 'zeros_like'] + +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] diff --git a/spec/API_specification/array_api/data_type_functions.py b/spec/API_specification/array_api/data_type_functions.py index 6b1b242ae..0f557852b 100644 --- a/spec/API_specification/array_api/data_type_functions.py +++ b/spec/API_specification/array_api/data_type_functions.py @@ -1,5 +1,6 @@ from ._types import Union, Tuple, array, dtype, finfo_object, iinfo_object + def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: """ Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. @@ -37,6 +38,7 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: an array having the specified data type. The returned array must have the same shape as ``x``. """ + def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: """ Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. @@ -54,6 +56,7 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. """ + def finfo(type: Union[dtype, array], /) -> finfo_object: """ Machine limits for floating-point data types. @@ -96,6 +99,7 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: real-valued floating-point data type. """ + def iinfo(type: Union[dtype, array], /) -> iinfo_object: """ Machine limits for integer data types. @@ -127,7 +131,10 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: integer data type. """ -def isdtype(dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]]) -> bool: + +def isdtype( + dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]] +) -> bool: """ Returns a boolean indicating whether a provided dtype is of a specified data type "kind". @@ -142,7 +149,7 @@ def isdtype(dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]] - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: - **bool**: boolean data types (e.g., ``bool``). - - **signed integer**: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - **signed integer**: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). - **unsigned integer**: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). - **integral**: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. - **real floating**: real-valued floating-point data types (e.g., ``float32``, ``float64``). @@ -162,6 +169,7 @@ def isdtype(dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]] boolean indicating whether a provided dtype is of a specified data type kind. """ + def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: """ Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. @@ -180,4 +188,5 @@ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: the dtype resulting from an operation involving the input arrays and dtypes. """ -__all__ = ['astype', 'can_cast', 'finfo', 'iinfo', 'isdtype', 'result_type'] + +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] diff --git a/spec/API_specification/array_api/data_types.py b/spec/API_specification/array_api/data_types.py index a86c9ebe6..614807414 100644 --- a/spec/API_specification/array_api/data_types.py +++ b/spec/API_specification/array_api/data_types.py @@ -1,5 +1,6 @@ from ._types import dtype + def __eq__(self: dtype, other: dtype, /) -> bool: """ Computes the truth value of ``self == other`` in order to test for data type object equality. @@ -17,4 +18,5 @@ def __eq__(self: dtype, other: dtype, /) -> bool: a boolean indicating whether the data type objects are equal. """ -__all__ = ['__eq__'] + +__all__ = ["__eq__"] diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index b97c13c71..3a3743ba8 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -1,5 +1,6 @@ from ._types import array + def abs(x: array, /) -> array: r""" Calculates the absolute value for each element ``x_i`` of the input array ``x``. @@ -50,6 +51,7 @@ def abs(x: array, /) -> array: an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). """ + def acos(x: array, /) -> array: r""" Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element ``x_i`` of the input array ``x``. @@ -81,7 +83,7 @@ def acos(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. .. note:: - The principal value of the arc cosine of a complex number :math:`z` is + The principal value of the arc cosine of a complex number :math:`z` is .. math:: \operatorname{acos}(z) = \frac{1}{2}\pi + j\ \ln(zj + \sqrt{1-z^2}) @@ -99,7 +101,7 @@ def acos(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \pi]` along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -112,6 +114,7 @@ def acos(x: array, /) -> array: an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def acosh(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. @@ -179,6 +182,7 @@ def acosh(x: array, /) -> array: an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def add(x1: array, x2: array, /) -> array: """ Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -240,6 +244,7 @@ def add(x1: array, x2: array, /) -> array: an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. """ + def asin(x: array, /) -> array: r""" Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element ``x_i`` of the input array ``x``. @@ -267,7 +272,7 @@ def asin(x: array, /) -> array: For any :math:`z`, .. math:: - \operatorname{asin}(z) = \operatorname{acos}(-z) - \frac{\pi}{2} + \operatorname{asin}(z) = \operatorname{acos}(-z) - \frac{\pi}{2} .. note:: For complex floating-point operands, ``asin(conj(x))`` must equal ``conj(asin(x))``. @@ -277,7 +282,7 @@ def asin(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse sine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -290,6 +295,7 @@ def asin(x: array, /) -> array: an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def asinh(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. @@ -348,6 +354,7 @@ def asinh(x: array, /) -> array: an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def atan(x: array, /) -> array: r""" Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. @@ -393,6 +400,7 @@ def atan(x: array, /) -> array: an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def atan2(x1: array, x2: array, /) -> array: """ Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. @@ -446,6 +454,7 @@ def atan2(x1: array, x2: array, /) -> array: """ + def atanh(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element ``x_i`` of the input array ``x``. @@ -508,6 +517,7 @@ def atanh(x: array, /) -> array: an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def bitwise_and(x1: array, x2: array, /) -> array: """ Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -525,6 +535,7 @@ def bitwise_and(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_left_shift(x1: array, x2: array, /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. @@ -542,6 +553,7 @@ def bitwise_left_shift(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_invert(x: array, /) -> array: """ Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. @@ -557,6 +569,7 @@ def bitwise_invert(x: array, /) -> array: an array containing the element-wise results. The returned array must have the same data type as ``x``. """ + def bitwise_or(x1: array, x2: array, /) -> array: """ Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -574,6 +587,7 @@ def bitwise_or(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_right_shift(x1: array, x2: array, /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. @@ -594,6 +608,7 @@ def bitwise_right_shift(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_xor(x1: array, x2: array, /) -> array: """ Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -611,6 +626,7 @@ def bitwise_xor(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def ceil(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. @@ -638,6 +654,7 @@ def ceil(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def conj(x: array, /) -> array: """ Returns the complex conjugate for each element ``x_i`` of the input array ``x``. @@ -706,6 +723,7 @@ def cos(x: array, /) -> array: an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def cosh(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the hyperbolic cosine for each element ``x_i`` in the input array ``x``. @@ -762,6 +780,7 @@ def cosh(x: array, /) -> array: an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def divide(x1: array, x2: array, /) -> array: r""" Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -811,17 +830,17 @@ def divide(x1: array, x2: array, /) -> array: +------------+----------------+-----------------+--------------------------+ In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. - + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division - + .. math:: \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} - + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, - + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. - In the remaining cases, the result is implementation dependent. - + .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. @@ -838,6 +857,7 @@ def divide(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def equal(x1: array, x2: array, /) -> array: r""" Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -875,6 +895,7 @@ def equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def exp(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). @@ -924,6 +945,7 @@ def exp(x: array, /) -> array: an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def expm1(x: array, /) -> array: """ Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. @@ -976,6 +998,7 @@ def expm1(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def floor(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. @@ -1003,6 +1026,7 @@ def floor(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def floor_divide(x1: array, x2: array, /) -> array: r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. @@ -1059,6 +1083,7 @@ def floor_divide(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def greater(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1079,6 +1104,7 @@ def greater(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def greater_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1099,6 +1125,7 @@ def greater_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def imag(x: array, /) -> array: """ Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. @@ -1111,9 +1138,10 @@ def imag(x: array, /) -> array: Returns ------- out: array - an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). """ + def isfinite(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if finite. @@ -1144,6 +1172,7 @@ def isfinite(x: array, /) -> array: an array containing test results. The returned array must have a data type of ``bool``. """ + def isinf(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. @@ -1172,6 +1201,7 @@ def isinf(x: array, /) -> array: an array containing test results. The returned array must have a data type of ``bool``. """ + def isnan(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. @@ -1199,6 +1229,7 @@ def isnan(x: array, /) -> array: an array containing test results. The returned array should have a data type of ``bool``. """ + def less(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1219,6 +1250,7 @@ def less(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def less_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1239,6 +1271,7 @@ def less_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def log(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm for each element ``x_i`` of the input array ``x``. @@ -1281,7 +1314,7 @@ def log(x: array, /) -> array: Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -1294,6 +1327,7 @@ def log(x: array, /) -> array: an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log1p(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. @@ -1328,7 +1362,7 @@ def log1p(x: array, /) -> array: .. note:: For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. - + .. note:: By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. @@ -1349,6 +1383,7 @@ def log1p(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log2(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. @@ -1384,6 +1419,7 @@ def log2(x: array, /) -> array: an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log10(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. @@ -1419,6 +1455,7 @@ def log10(x: array, /) -> array: an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def logaddexp(x1: array, x2: array, /) -> array: """ Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1444,6 +1481,7 @@ def logaddexp(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. """ + def logical_and(x1: array, x2: array, /) -> array: """ Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1464,6 +1502,7 @@ def logical_and(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of `bool`. """ + def logical_not(x: array, /) -> array: """ Computes the logical NOT for each element ``x_i`` of the input array ``x``. @@ -1482,6 +1521,7 @@ def logical_not(x: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def logical_or(x1: array, x2: array, /) -> array: """ Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1502,6 +1542,7 @@ def logical_or(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def logical_xor(x1: array, x2: array, /) -> array: """ Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1522,6 +1563,7 @@ def logical_xor(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def multiply(x1: array, x2: array, /) -> array: r""" Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1583,6 +1625,7 @@ def multiply(x1: array, x2: array, /) -> array: an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. """ + def negative(x: array, /) -> array: """ Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. @@ -1604,6 +1647,7 @@ def negative(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def not_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1639,6 +1683,7 @@ def not_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def positive(x: array, /) -> array: """ Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. @@ -1654,6 +1699,7 @@ def positive(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def pow(x1: array, x2: array, /) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. @@ -1717,6 +1763,7 @@ def pow(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def real(x: array, /) -> array: """ Returns the real component of a complex number for each element ``x_i`` of the input array ``x``. @@ -1729,9 +1776,10 @@ def real(x: array, /) -> array: Returns ------- out: array - an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). """ + def remainder(x1: array, x2: array, /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. @@ -1783,13 +1831,14 @@ def remainder(x1: array, x2: array, /) -> array: an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def round(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. .. note:: For complex floating-point operands, real and imaginary components must be independently rounded to the nearest integer-valued number. - + Rounded real and imaginary components must be equal to their equivalent rounded real-valued floating-point counterparts (i.e., for complex-valued ``x``, ``real(round(x))`` must equal ``round(real(x)))`` and ``imag(round(x))`` must equal ``round(imag(x))``). **Special cases** @@ -1819,6 +1868,7 @@ def round(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def sign(x: array, /) -> array: r""" Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. @@ -1859,6 +1909,7 @@ def sign(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def sin(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. @@ -1898,6 +1949,7 @@ def sin(x: array, /) -> array: an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def sinh(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the hyperbolic sine for each element ``x_i`` of the input array ``x``. @@ -1954,6 +2006,7 @@ def sinh(x: array, /) -> array: an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def square(x: array, /) -> array: r""" Squares each element ``x_i`` of the input array ``x``. @@ -1978,6 +2031,7 @@ def square(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def sqrt(x: array, /) -> array: r""" Calculates the principal square root for each element ``x_i`` of the input array ``x``. @@ -2018,7 +2072,7 @@ def sqrt(x: array, /) -> array: Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). - + Parameters ---------- x: array @@ -2030,6 +2084,7 @@ def sqrt(x: array, /) -> array: an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def subtract(x1: array, x2: array, /) -> array: """ Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -2049,6 +2104,7 @@ def subtract(x1: array, x2: array, /) -> array: an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. """ + def tan(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the tangent for each element ``x_i`` of the input array ``x``. @@ -2088,6 +2144,7 @@ def tan(x: array, /) -> array: an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def tanh(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the hyperbolic tangent for each element ``x_i`` of the input array ``x``. @@ -2148,6 +2205,7 @@ def tanh(x: array, /) -> array: an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def trunc(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. @@ -2175,4 +2233,65 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'conj', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'imag', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'real', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] + +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "conj", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "real", + "remainder", + "round", + "sign", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] diff --git a/spec/API_specification/array_api/fft.py b/spec/API_specification/array_api/fft.py index ac292ceb9..2eb428b0c 100644 --- a/spec/API_specification/array_api/fft.py +++ b/spec/API_specification/array_api/fft.py @@ -1,7 +1,14 @@ from ._types import Tuple, Union, Sequence, array, Optional, Literal, device -def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def fft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the one-dimensional discrete Fourier transform. @@ -40,7 +47,14 @@ def fft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[' """ -def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def ifft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the one-dimensional inverse discrete Fourier transform. @@ -79,7 +93,14 @@ def ifft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ """ -def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def fftn( + x: array, + /, + *, + s: Sequence[int] = None, + axes: Sequence[int] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the n-dimensional discrete Fourier transform. @@ -125,7 +146,14 @@ def fftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, no """ -def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def ifftn( + x: array, + /, + *, + s: Sequence[int] = None, + axes: Sequence[int] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the n-dimensional inverse discrete Fourier transform. @@ -171,7 +199,14 @@ def ifftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n """ -def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def rfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the one-dimensional discrete Fourier transform for real-valued input. @@ -210,7 +245,14 @@ def rfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ """ -def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def irfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the one-dimensional inverse of ``rfft`` for complex-valued input. @@ -249,7 +291,14 @@ def irfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal """ -def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def rfftn( + x: array, + /, + *, + s: Sequence[int] = None, + axes: Sequence[int] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the n-dimensional discrete Fourier transform for real-valued input. @@ -295,7 +344,14 @@ def rfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, n """ -def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def irfftn( + x: array, + /, + *, + s: Sequence[int] = None, + axes: Sequence[int] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the n-dimensional inverse of ``rfftn`` for complex-valued input. @@ -341,7 +397,14 @@ def irfftn(x: array, /, *, s: Sequence[int] = None, axes: Sequence[int] = None, """ -def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def hfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. @@ -377,7 +440,14 @@ def hfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal[ """ -def ihfft(x: array, /, *, n: Optional[int] = None, axis: int = -1, norm: Literal['backward', 'ortho', 'forward'] = 'backward') -> array: +def ihfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: """ Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. @@ -513,4 +583,19 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: """ -__all__ = ['fft','ifft','fftn','ifftn','rfft','irfft','rfftn','irfftn','hfft','ihfft','fftfreq','rfftfreq','fftshift','ifftshift'] +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] diff --git a/spec/API_specification/array_api/indexing_functions.py b/spec/API_specification/array_api/indexing_functions.py index 65f2c3450..e76ce7484 100644 --- a/spec/API_specification/array_api/indexing_functions.py +++ b/spec/API_specification/array_api/indexing_functions.py @@ -1,5 +1,6 @@ from ._types import Union, array + def take(x: array, indices: array, /, *, axis: int) -> array: """ Returns elements of an array along an axis. @@ -24,4 +25,5 @@ def take(x: array, indices: array, /, *, axis: int) -> array: 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'] + +__all__ = ["take"] diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index faa8ba9e6..6bcd37570 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -1,6 +1,7 @@ from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype from .constants import inf + def cholesky(x: array, /, *, upper: bool = False) -> array: r""" Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. @@ -39,6 +40,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ + def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Returns the cross product of 3-element vectors. @@ -71,6 +73,7 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: - if the size of the axis over which to compute the cross product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ + def det(x: array, /) -> array: """ Returns the determinant of a square matrix (or a stack of square matrices) ``x``. @@ -86,6 +89,7 @@ def det(x: array, /) -> array: if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. """ + def diagonal(x: array, /, *, offset: int = 0) -> array: """ Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. @@ -109,6 +113,7 @@ def diagonal(x: array, /, *, offset: int = 0) -> array: an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. """ + def eigh(x: array, /) -> Tuple[array]: r""" Returns an eigenvalue decomposition of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. @@ -154,6 +159,7 @@ def eigh(x: array, /) -> Tuple[array]: Eigenvalue sort order is left unspecified and is thus implementation-dependent. """ + def eigvalsh(x: array, /) -> array: r""" Returns the eigenvalues of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. @@ -191,6 +197,7 @@ def eigvalsh(x: array, /) -> array: Eigenvalue sort order is left unspecified and is thus implementation-dependent. """ + def inv(x: array, /) -> array: r""" Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. @@ -219,12 +226,20 @@ def inv(x: array, /) -> array: an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ + def matmul(x1: array, x2: array, /) -> array: """ Alias for :func:`~array_api.matmul`. """ -def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: + +def matrix_norm( + x: array, + /, + *, + keepdims: bool = False, + ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro", +) -> array: """ Computes the matrix norm of a matrix (or a stack of matrices) ``x``. @@ -277,6 +292,7 @@ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). """ + def matrix_power(x: array, n: int, /) -> array: """ Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. @@ -294,6 +310,7 @@ def matrix_power(x: array, n: int, /) -> array: if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. """ + def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: """ Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). @@ -313,11 +330,13 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). """ + def matrix_transpose(x: array, /) -> array: """ Alias for :func:`~array_api.matrix_transpose`. """ + def outer(x1: array, x2: array, /) -> array: """ Returns the outer product of two vectors ``x1`` and ``x2``. @@ -335,6 +354,7 @@ def outer(x1: array, x2: array, /) -> array: a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: r""" Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. @@ -368,7 +388,10 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). """ -def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tuple[array, array]: + +def qr( + x: array, /, *, mode: Literal["reduced", "complete"] = "reduced" +) -> Tuple[array, array]: r""" Returns the QR decomposition of a full column rank matrix (or a stack of matrices). @@ -424,6 +447,7 @@ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tupl Each returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def slogdet(x: array, /) -> Tuple[array, array]: r""" Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. @@ -472,6 +496,7 @@ def slogdet(x: array, /) -> Tuple[array, array]: Each returned array must have shape ``shape(x)[:-2]``. """ + def solve(x1: array, x2: array, /) -> array: r""" Returns the solution of a square system of linear equations with a unique solution. @@ -503,6 +528,7 @@ def solve(x1: array, x2: array, /) -> array: an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. """ + def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: r""" Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. @@ -551,6 +577,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. """ + def svdvals(x: array, /) -> array: """ Returns the singular values of a matrix (or a stack of matrices) ``x``. @@ -568,11 +595,19 @@ def svdvals(x: array, /) -> array: an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). """ -def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: """ Alias for :func:`~array_api.tensordot`. """ + def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> array: """ Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. @@ -623,12 +658,21 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr The returned array must have a data type as described by the ``dtype`` parameter above. """ + def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ Alias for :func:`~array_api.vecdot`. """ -def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: + +def vector_norm( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, + ord: Union[int, float, Literal[inf, -inf]] = 2, +) -> array: r""" Computes the vector norm of a vector (or batch of vectors) ``x``. @@ -679,4 +723,29 @@ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = No an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). """ -__all__ = ['cholesky', 'cross', 'det', 'diagonal', 'eigh', 'eigvalsh', 'inv', 'matmul', 'matrix_norm', 'matrix_power', 'matrix_rank', 'matrix_transpose', 'outer', 'pinv', 'qr', 'slogdet', 'solve', 'svd', 'svdvals', 'tensordot', 'trace', 'vecdot', 'vector_norm'] + +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py index 6507c37cd..74559aca8 100644 --- a/spec/API_specification/array_api/linear_algebra_functions.py +++ b/spec/API_specification/array_api/linear_algebra_functions.py @@ -1,5 +1,6 @@ from ._types import Tuple, Union, Sequence, array + def matmul(x1: array, x2: array, /) -> array: """ Computes the matrix product. @@ -41,6 +42,7 @@ def matmul(x1: array, x2: array, /) -> array: - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. """ + def matrix_transpose(x: array, /) -> array: """ Transposes a matrix (or a stack of matrices) ``x``. @@ -56,7 +58,14 @@ def matrix_transpose(x: array, /) -> array: an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. """ -def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: """ Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. @@ -94,15 +103,16 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Computes the (vector) dot product of two arrays. - + Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as - + .. math:: \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} a_i\overline{b_i} - + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{b_i}` denotes the complex conjugate if :math:`b_i` is complex and the identity if :math:`b_i` is real-valued. Parameters @@ -130,4 +140,5 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ -__all__ = ['matmul', 'matrix_transpose', 'tensordot', 'vecdot'] + +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] diff --git a/spec/API_specification/array_api/manipulation_functions.py b/spec/API_specification/array_api/manipulation_functions.py index 9d355f9e5..314f4627e 100644 --- a/spec/API_specification/array_api/manipulation_functions.py +++ b/spec/API_specification/array_api/manipulation_functions.py @@ -1,5 +1,6 @@ from ._types import List, Optional, Tuple, Union, array + def broadcast_arrays(*arrays: array) -> List[array]: """ Broadcasts one or more arrays against one another. @@ -15,6 +16,7 @@ def broadcast_arrays(*arrays: array) -> List[array]: a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. """ + def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: """ Broadcasts an array to a specified shape. @@ -32,7 +34,10 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: an array having a specified shape. Must have the same data type as ``x``. """ -def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0) -> array: + +def concat( + arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0 +) -> array: """ Joins a sequence of arrays along an existing axis. @@ -52,6 +57,7 @@ def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[i This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. """ + def expand_dims(x: array, /, *, axis: int = 0) -> array: """ Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. @@ -69,6 +75,7 @@ def expand_dims(x: array, /, *, axis: int = 0) -> array: an expanded output array having the same data type as ``x``. """ + def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: """ Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. @@ -86,6 +93,7 @@ def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. """ + def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: """ Permutes the axes (dimensions) of an array ``x``. @@ -103,7 +111,10 @@ def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: an array containing the axes permutation. The returned array must have the same data type as ``x``. """ -def reshape(x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None) -> array: + +def reshape( + x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None +) -> array: """ Reshapes an array without changing its data. @@ -122,7 +133,14 @@ def reshape(x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None) an output array having the same data type and elements as ``x``. """ -def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + +def roll( + x: array, + /, + shift: Union[int, Tuple[int, ...]], + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, +) -> array: """ Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. @@ -141,6 +159,7 @@ def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Unio an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. """ + def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: """ Removes singleton dimensions (axes) from ``x``. @@ -158,6 +177,7 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: an output array having the same data type and elements as ``x``. """ + def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: """ Joins a sequence of arrays along a new axis. @@ -178,4 +198,16 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. """ -__all__ = [ 'broadcast_arrays', 'broadcast_to', 'concat', 'expand_dims', 'flip', 'permute_dims', 'reshape', 'roll', 'squeeze', 'stack'] \ No newline at end of file + +__all__ = [ + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "permute_dims", + "reshape", + "roll", + "squeeze", + "stack", +] diff --git a/spec/API_specification/array_api/searching_functions.py b/spec/API_specification/array_api/searching_functions.py index 1db08f287..9393ba71e 100644 --- a/spec/API_specification/array_api/searching_functions.py +++ b/spec/API_specification/array_api/searching_functions.py @@ -1,5 +1,6 @@ from ._types import Optional, Tuple, array + def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ Returns the indices of the maximum values along a specified axis. @@ -24,6 +25,7 @@ def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. """ + def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ Returns the indices of the minimum values along a specified axis. @@ -48,6 +50,7 @@ def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. """ + def nonzero(x: array, /) -> Tuple[array, ...]: """ Returns the indices of the array elements which are non-zero. @@ -74,6 +77,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. """ + def where(condition: array, x1: array, x2: array, /) -> array: """ Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. @@ -93,4 +97,5 @@ def where(condition: array, x1: array, x2: array, /) -> array: an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. """ -__all__ = ['argmax', 'argmin', 'nonzero', 'where'] + +__all__ = ["argmax", "argmin", "nonzero", "where"] diff --git a/spec/API_specification/array_api/set_functions.py b/spec/API_specification/array_api/set_functions.py index 34ae41848..dc95f58e8 100644 --- a/spec/API_specification/array_api/set_functions.py +++ b/spec/API_specification/array_api/set_functions.py @@ -1,5 +1,6 @@ from ._types import Tuple, array + 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``. @@ -39,6 +40,7 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_counts(x: array, /) -> Tuple[array, array]: """ Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. @@ -74,6 +76,7 @@ def unique_counts(x: array, /) -> Tuple[array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_inverse(x: array, /) -> Tuple[array, array]: """ Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. @@ -109,6 +112,7 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_values(x: array, /) -> array: """ Returns the unique elements of an input array ``x``. @@ -139,4 +143,5 @@ def unique_values(x: array, /) -> array: The order of unique elements is not specified and may vary between implementations. """ -__all__ = ['unique_all', 'unique_counts', 'unique_inverse', 'unique_values'] \ No newline at end of file + +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] diff --git a/spec/API_specification/array_api/sorting_functions.py b/spec/API_specification/array_api/sorting_functions.py index 53732d535..3eb52c8ce 100644 --- a/spec/API_specification/array_api/sorting_functions.py +++ b/spec/API_specification/array_api/sorting_functions.py @@ -1,6 +1,9 @@ from ._types import array -def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + +def argsort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: """ Returns the indices that sort an array ``x`` along a specified axis. @@ -24,7 +27,10 @@ def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bo an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. """ -def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + +def sort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: """ Returns a sorted copy of an input array ``x``. @@ -48,4 +54,5 @@ def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool a sorted array. The returned array must have the same data type and shape as ``x``. """ -__all__ = ['argsort', 'sort'] \ No newline at end of file + +__all__ = ["argsort", "sort"] diff --git a/spec/API_specification/array_api/statistical_functions.py b/spec/API_specification/array_api/statistical_functions.py index a49fe4bec..24ef810af 100644 --- a/spec/API_specification/array_api/statistical_functions.py +++ b/spec/API_specification/array_api/statistical_functions.py @@ -1,6 +1,13 @@ from ._types import Optional, Tuple, Union, array, dtype -def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def max( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the maximum value of the input array ``x``. @@ -31,7 +38,14 @@ def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. """ -def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def mean( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the arithmetic mean of the input array ``x``. @@ -60,7 +74,14 @@ def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, kee While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. """ -def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def min( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the minimum value of the input array ``x``. @@ -91,7 +112,15 @@ def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. """ -def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + +def prod( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: """ Calculates the product of input array ``x`` elements. @@ -132,7 +161,15 @@ def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dty if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. """ -def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + +def std( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: """ Calculates the standard deviation of the input array ``x``. @@ -163,7 +200,15 @@ def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. """ -def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + +def sum( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: """ Calculates the sum of the input array ``x``. @@ -204,7 +249,15 @@ def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtyp if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. """ -def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + +def var( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: """ Calculates the variance of the input array ``x``. @@ -236,4 +289,5 @@ def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. """ -__all__ = ['max', 'mean', 'min', 'prod', 'std', 'sum', 'var'] + +__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] diff --git a/spec/API_specification/array_api/utility_functions.py b/spec/API_specification/array_api/utility_functions.py index c05cb948e..e70fe8aa6 100644 --- a/spec/API_specification/array_api/utility_functions.py +++ b/spec/API_specification/array_api/utility_functions.py @@ -1,6 +1,13 @@ from ._types import Optional, Tuple, Union, array -def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def all( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Tests whether all input array elements evaluate to ``True`` along a specified axis. @@ -28,7 +35,14 @@ def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. """ -def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def any( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Tests whether any input array element evaluates to ``True`` along a specified axis. @@ -56,4 +70,5 @@ def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. """ -__all__ = ['all', 'any'] + +__all__ = ["all", "any"] From 8e3c395a00396c99403248e6745f3d243f4fc636 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 14 Dec 2022 23:01:45 +0100 Subject: [PATCH 339/551] Add a `.git-blame-ignore-revs` file to ignore style change commits See https://black.readthedocs.io/en/stable/guides/introducing_black_to_your_project.html#avoiding-ruining-git-blame and https://docs.github.com/en/repositories/working-with-files/using-files/viewing-a-file#ignore-commits-in-the-blame-view Tested that this works out of the box in the GitHub UI, and locally after running: git config blame.ignoreRevsFile .git-blame-ignore-revs --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 000000000..8fd251e32 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# Migrate code style to Black +162034b12711dad54589c5dc9e75942695a7957f From 8a162470c883aa58153ff6b287d1f42a0a7f8430 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 15 Dec 2022 13:45:42 +0100 Subject: [PATCH 340/551] Fix some style issues in docstrings, make pydocstyle check pass The check to run is: ``` pydocstyle . --ignore=D401,D212,D413,D100 --match='(?!_types.py).*\.py' ``` `_types.py` is excluded because it's a private file, and it's too fiddly and not necessary to add docstrings to the classes in that file. --- spec/API_specification/array_api/__init__.py | 2 ++ spec/API_specification/array_api/_types.py | 4 +++- spec/API_specification/array_api/array_object.py | 4 +--- .../array_api/creation_functions.py | 2 +- spec/API_specification/array_api/linalg.py | 16 ++++------------ .../array_api/linear_algebra_functions.py | 2 +- .../array_api/manipulation_functions.py | 2 +- 7 files changed, 13 insertions(+), 19 deletions(-) diff --git a/spec/API_specification/array_api/__init__.py b/spec/API_specification/array_api/__init__.py index 5368c8325..32f88750d 100644 --- a/spec/API_specification/array_api/__init__.py +++ b/spec/API_specification/array_api/__init__.py @@ -1,3 +1,5 @@ +"""Function stubs and API documentation for the array API standard.""" + from .array_object import * from .constants import * from .creation_functions import * diff --git a/spec/API_specification/array_api/_types.py b/spec/API_specification/array_api/_types.py index be81b40ae..4a60040d5 100644 --- a/spec/API_specification/array_api/_types.py +++ b/spec/API_specification/array_api/_types.py @@ -1,5 +1,5 @@ """ -This file defines the types for type annotations. +Types for type annotations used in the array API standard. The type variables should be replaced with the actual types for a given library, e.g., for NumPy TypeVar('array') would be replaced with ndarray. @@ -33,6 +33,7 @@ @dataclass class finfo_object: + """Dataclass returned by `finfo`.""" bits: int eps: float max: float @@ -42,6 +43,7 @@ class finfo_object: @dataclass class iinfo_object: + """Dataclass returned by `iinfo`.""" bits: int max: int min: int diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 3dee8c5ab..7c92800d0 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -16,9 +16,7 @@ class _array: def __init__(self: array) -> None: - """ - Initialize the attributes for the array object class. - """ + """Initialize the attributes for the array object class.""" @property def dtype(self: array) -> Dtype: diff --git a/spec/API_specification/array_api/creation_functions.py b/spec/API_specification/array_api/creation_functions.py index bfb89b2ba..3f577b542 100644 --- a/spec/API_specification/array_api/creation_functions.py +++ b/spec/API_specification/array_api/creation_functions.py @@ -156,7 +156,7 @@ def eye( dtype: Optional[dtype] = None, device: Optional[device] = None, ) -> array: - """ + r""" Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. .. note:: diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 6bcd37570..65e25bc5e 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -228,9 +228,7 @@ def inv(x: array, /) -> array: def matmul(x1: array, x2: array, /) -> array: - """ - Alias for :func:`~array_api.matmul`. - """ + """Alias for :func:`~array_api.matmul`.""" def matrix_norm( @@ -332,9 +330,7 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a def matrix_transpose(x: array, /) -> array: - """ - Alias for :func:`~array_api.matrix_transpose`. - """ + """Alias for :func:`~array_api.matrix_transpose`.""" def outer(x1: array, x2: array, /) -> array: @@ -603,9 +599,7 @@ def tensordot( *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, ) -> array: - """ - Alias for :func:`~array_api.tensordot`. - """ + """Alias for :func:`~array_api.tensordot`.""" def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> array: @@ -660,9 +654,7 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: - """ - Alias for :func:`~array_api.vecdot`. - """ + """Alias for :func:`~array_api.vecdot`.""" def vector_norm( diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/spec/API_specification/array_api/linear_algebra_functions.py index 74559aca8..c8b6e50f8 100644 --- a/spec/API_specification/array_api/linear_algebra_functions.py +++ b/spec/API_specification/array_api/linear_algebra_functions.py @@ -105,7 +105,7 @@ def tensordot( def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: - """ + r""" Computes the (vector) dot product of two arrays. Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as diff --git a/spec/API_specification/array_api/manipulation_functions.py b/spec/API_specification/array_api/manipulation_functions.py index 314f4627e..2d7179a8b 100644 --- a/spec/API_specification/array_api/manipulation_functions.py +++ b/spec/API_specification/array_api/manipulation_functions.py @@ -190,7 +190,7 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> axis along which the arrays will be joined. Providing an ``axis`` specifies the index of the new axis in the dimensions of the result. For example, if ``axis`` is ``0``, the new axis will be the first dimension and the output array will have shape ``(N, A, B, C)``; if ``axis`` is ``1``, the new axis will be the second dimension and the output array will have shape ``(A, N, B, C)``; and, if ``axis`` is ``-1``, the new axis will be the last dimension and the output array will have shape ``(A, B, C, N)``. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. Returns - -------- + ------- out: array an output array having rank ``N+1``, where ``N`` is the rank (number of dimensions) of ``x``. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. From bb0cc71443000ad6aa3b9e9d04b317ec1f4d6b2d Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 15 Dec 2022 05:18:20 -0800 Subject: [PATCH 341/551] Consolidate complex number design topics and add guidance on value-based promotion (#573) --- spec/design_topics/branch_cuts.rst | 17 ------ .../design_topics/complex_number_ordering.rst | 19 ------- spec/design_topics/complex_numbers.rst | 53 ++++++++++++++++++- spec/design_topics/index.rst | 2 - 4 files changed, 52 insertions(+), 39 deletions(-) delete mode 100644 spec/design_topics/branch_cuts.rst delete mode 100644 spec/design_topics/complex_number_ordering.rst diff --git a/spec/design_topics/branch_cuts.rst b/spec/design_topics/branch_cuts.rst deleted file mode 100644 index 6989afbc7..000000000 --- a/spec/design_topics/branch_cuts.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _branch-cuts: - -Branch Cuts -=========== - -In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. - -For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. - -Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. - -In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. - -.. warning:: - All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. - - Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. \ No newline at end of file diff --git a/spec/design_topics/complex_number_ordering.rst b/spec/design_topics/complex_number_ordering.rst deleted file mode 100644 index 25ad215cd..000000000 --- a/spec/design_topics/complex_number_ordering.rst +++ /dev/null @@ -1,19 +0,0 @@ -.. _complex-number-ordering: - -Complex Number Ordering -======================= - -Given a set :math:`\{a_1, \ldots, a_n\}`, an order relation must satisfy the following properties: - -1. **Reflexive**: for any :math:`a` in the set, :math:`a \leq a`. -2. **Transitive**: for any :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`b \leq c`, then :math:`a \leq c`. -3. **Antisymmetric**: for any :math:`a` and :math:`b` in the set, if :math:`a \leq b` and :math:`b \leq a`, then :math:`a = b`. -4. **Total Order**: in addition to the *partial order* established by 1-3, for any :math:`a` and :math:`b` in the set, either :math:`a \leq b` or :math:`b \leq a` (or both). -5. **Compatible with Addition**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b`, then :math:`a + c \leq b + c`. -6. **Compatible with Multiplication**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`0 \leq c`, then :math:`ac \leq bc`. - -Defining an order relation for complex numbers which satisfies all six properties defined above is not possible. Accordingly, this specification does not require that a conforming implementation of the array API standard adopt any specific complex number order relation. - -In order to satisfy backward compatibility guarantees, conforming implementations of the array API standard may choose to define an ordering for complex numbers (e.g., lexicographic); however, consumers of the array API standard should **not** assume that complex number ordering is consistent between implementations or even supported. - -If a conforming implementation chooses to define an ordering for complex numbers, the ordering must be clearly documented. \ No newline at end of file diff --git a/spec/design_topics/complex_numbers.rst b/spec/design_topics/complex_numbers.rst index 1fcba7e81..da441499a 100644 --- a/spec/design_topics/complex_numbers.rst +++ b/spec/design_topics/complex_numbers.rst @@ -3,8 +3,59 @@ Complex Numbers =============== +The Complex Plane +----------------- + Mathematically, equality comparison between complex numbers depends on the choice of topology. For example, the complex plane has a continuum of infinities; however, when the complex plane is projected onto the surface of a sphere (a stereographic projection commonly referred to as the *Riemann sphere*), infinities coalesce into a single *point at infinity*, thus modeling the extended complex plane. For the former, the value :math:`\infty + 3j` is distinct from (i.e., does not equal) :math:`\infty + 4j`, while, for the latter, :math:`\infty + 3j` does equal :math:`\infty + 4j`. Modeling complex numbers as a Riemann sphere conveys certain mathematical niceties (e.g., well-behaved division by zero and preservation of the identity :math:`\frac{1}{\frac{1}{z}} = z`); however, translating the model to IEEE 754 floating-point operations can lead to some unexpected results. For example, according to IEEE 754, :math:`+\infty` and :math:`-\infty` are distinct values; hence, for equality comparison, if :math:`x = +\infty` and :math:`y = -\infty`, then :math:`x \neq y`. In contrast, if we convert :math:`x` and :math:`y` to their complex number equivalents :math:`x = +\infty + 0j` and :math:`y = -\infty + 0j` and then interpret within the context of the extended complex plane, we arrive at the opposite result; namely, :math:`x = y`. -In short, given the constraints of floating-point arithmetic and the subtleties of signed zeros, infinities, NaNs, and their interaction, crafting a specification which always yields intuitive results and satisfies all use cases involving complex numbers is not possible. Instead, this specification attempts to follow precedent (e.g., C99, Python, Julia, NumPy, and elsewhere), while also minimizing surprise. The result is an imperfect balance in which certain APIs may appear to embrace the one-infinity model found in C/C++ for algebraic operations involving complex numbers (e.g., considering :math:`\infty + \operatorname{NaN}\ j` to be infinite, irrespective of the imaginary component's value, including NaN), while other APIs may rely on the complex plane with its multiplicity of infinities (e.g., in transcendental functions). Accordingly, consumers of this specification should expect that certain results involving complex numbers for one operation may not be wholly consistent with results involving complex numbers for another operation. \ No newline at end of file +In short, given the constraints of floating-point arithmetic and the subtleties of signed zeros, infinities, NaNs, and their interaction, crafting a specification which always yields intuitive results and satisfies all use cases involving complex numbers is not possible. Instead, this specification attempts to follow precedent (e.g., C99, Python, Julia, NumPy, and elsewhere), while also minimizing surprise. The result is an imperfect balance in which certain APIs may appear to embrace the one-infinity model found in C/C++ for algebraic operations involving complex numbers (e.g., considering :math:`\infty + \operatorname{NaN}\ j` to be infinite, irrespective of the imaginary component's value, including NaN), while other APIs may rely on the complex plane with its multiplicity of infinities (e.g., in transcendental functions). Accordingly, consumers of this specification should expect that certain results involving complex numbers for one operation may not be wholly consistent with results involving complex numbers for another operation. + + +.. _branch-cuts: + +Branch Cuts +----------- + +In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. + +For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. + +Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. + +In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. + +.. warning:: + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. + + +.. _complex-number-ordering: + +Complex Number Ordering +----------------------- + +Given a set :math:`\{a_1, \ldots, a_n\}`, an order relation must satisfy the following properties: + +1. **Reflexive**: for any :math:`a` in the set, :math:`a \leq a`. +2. **Transitive**: for any :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`b \leq c`, then :math:`a \leq c`. +3. **Antisymmetric**: for any :math:`a` and :math:`b` in the set, if :math:`a \leq b` and :math:`b \leq a`, then :math:`a = b`. +4. **Total Order**: in addition to the *partial order* established by 1-3, for any :math:`a` and :math:`b` in the set, either :math:`a \leq b` or :math:`b \leq a` (or both). +5. **Compatible with Addition**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b`, then :math:`a + c \leq b + c`. +6. **Compatible with Multiplication**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`0 \leq c`, then :math:`ac \leq bc`. + +Defining an order relation for complex numbers which satisfies all six properties defined above is not possible. Accordingly, this specification does not require that a conforming implementation of the array API standard adopt any specific complex number order relation. + +In order to satisfy backward compatibility guarantees, conforming implementations of the array API standard may choose to define an ordering for complex numbers (e.g., lexicographic); however, consumers of the array API standard should **not** assume that complex number ordering is consistent between implementations or even supported. + +If a conforming implementation chooses to define an ordering for complex numbers, the ordering must be clearly documented. + + +Valued-based Promotion +---------------------- + +According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. + +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. \ No newline at end of file diff --git a/spec/design_topics/index.rst b/spec/design_topics/index.rst index 13e2c8825..c8c5a0733 100644 --- a/spec/design_topics/index.rst +++ b/spec/design_topics/index.rst @@ -12,7 +12,5 @@ Design topics & constraints static_typing accuracy complex_numbers - branch_cuts - complex_number_ordering C_API parallelism From b186a1c7922d61e9e045c28b09f49dc687908d08 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 15 Dec 2022 11:31:54 -0800 Subject: [PATCH 342/551] Add a changelog for tracking specification changes across versions (#574) --- CHANGELOG.md | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 000000000..002d4fec9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,199 @@ +# Changelog + +> Specification changelog. + +This changelog is organized by specification version and notes all changes with respect to the previous version. Within the section for a specific version (e.g., v2022.12), separate sections are used for (a) changes to existing APIs and requirements, (b) new APIs and new requirements, and (c) errata. + +## v2022.12 + +### Updates + +> Updates to existing APIs and requirements. + +#### APIs + +- `__bool__`: add support for non-boolean data types ([gh-497](https://github.com/data-apis/array-api/pull/497)) +- `__dlpack__`: raise `BufferError` when data cannot be exported as DLPack ([gh-498](https://github.com/data-apis/array-api/pull/498)) +- `__float__`: add support for non-floating-point data types ([gh-497](https://github.com/data-apis/array-api/pull/497)) +- `__int__`: add support for non-integer data types ([gh-497](https://github.com/data-apis/array-api/pull/497)) + +##### Complex Number Support + +The following APIs were updated to support arrays having complex floating-point data types: + +- `__abs__`([gh-546](https://github.com/data-apis/array-api/pull/546)) +- `__add__`([gh-525](https://github.com/data-apis/array-api/pull/525)) +- `__eq__`([gh-528](https://github.com/data-apis/array-api/pull/528)) +- `__matmul__`([gh-557](https://github.com/data-apis/array-api/pull/557)) +- `__mul__`([gh-551](https://github.com/data-apis/array-api/pull/551)) +- `__ne__`([gh-529](https://github.com/data-apis/array-api/pull/529)) +- `__neg__`([gh-448](https://github.com/data-apis/array-api/pull/448)) +- `__pos__`([gh-447](https://github.com/data-apis/array-api/pull/447)) +- `__pow__`([gh-537](https://github.com/data-apis/array-api/pull/537)) +- `__sub__`([gh-526](https://github.com/data-apis/array-api/pull/526)) +- `__truediv__`([gh-554](https://github.com/data-apis/array-api/pull/554)) +- `abs`([gh-546](https://github.com/data-apis/array-api/pull/546)) +- `acos`([gh-517](https://github.com/data-apis/array-api/pull/517)) +- `acosh`([gh-520](https://github.com/data-apis/array-api/pull/520)) +- `add`([gh-525](https://github.com/data-apis/array-api/pull/525)) +- `asin`([gh-521](https://github.com/data-apis/array-api/pull/521)) +- `asinh`([gh-522](https://github.com/data-apis/array-api/pull/522)) +- `atan`([gh-523](https://github.com/data-apis/array-api/pull/523)) +- `atanh`([gh-524](https://github.com/data-apis/array-api/pull/524)) +- `all`([gh-442](https://github.com/data-apis/array-api/pull/442)) +- `any`([gh-442](https://github.com/data-apis/array-api/pull/442)) +- `asarray`([gh-434](https://github.com/data-apis/array-api/pull/434)) +- `astype`([gh-445](https://github.com/data-apis/array-api/pull/445)) +- `cos`([gh-454](https://github.com/data-apis/array-api/pull/454)) +- `cosh`([gh-453](https://github.com/data-apis/array-api/pull/453)) +- `divide`([gh-554](https://github.com/data-apis/array-api/pull/554)) +- `equal`([gh-528](https://github.com/data-apis/array-api/pull/528)) +- `eye`([gh-436](https://github.com/data-apis/array-api/pull/436)) +- `exp`([gh-451](https://github.com/data-apis/array-api/pull/451)) +- `expm1`([gh-452](https://github.com/data-apis/array-api/pull/452)) +- `finfo`([gh-484](https://github.com/data-apis/array-api/pull/484)) +- `full`([gh-435](https://github.com/data-apis/array-api/pull/435)) +- `full_like`([gh-435](https://github.com/data-apis/array-api/pull/435)) +- `isfinite`([gh-531](https://github.com/data-apis/array-api/pull/531)) +- `isinf`([gh-530](https://github.com/data-apis/array-api/pull/530)) +- `isnan`([gh-532](https://github.com/data-apis/array-api/pull/532)) +- `linspace`([gh-568](https://github.com/data-apis/array-api/pull/568)) +- `log`([gh-514](https://github.com/data-apis/array-api/pull/514)) +- `log1p`([gh-534](https://github.com/data-apis/array-api/pull/534)) +- `log10`([gh-536](https://github.com/data-apis/array-api/pull/536)) +- `log2`([gh-535](https://github.com/data-apis/array-api/pull/535)) +- `matmul`([gh-557](https://github.com/data-apis/array-api/pull/557)) +- `meshgrid`([gh-437](https://github.com/data-apis/array-api/pull/437)) +- `multiply`([gh-551](https://github.com/data-apis/array-api/pull/551)) +- `negative`([gh-448](https://github.com/data-apis/array-api/pull/448)) +- `nonzero`([gh-441](https://github.com/data-apis/array-api/pull/441)) +- `not_equal`([gh-529](https://github.com/data-apis/array-api/pull/529)) +- `ones`([gh-438](https://github.com/data-apis/array-api/pull/438)) +- `ones_like`([gh-438](https://github.com/data-apis/array-api/pull/438)) +- `positive`([gh-447](https://github.com/data-apis/array-api/pull/447)) +- `pow`([gh-537](https://github.com/data-apis/array-api/pull/537)) +- `prod`([gh-553](https://github.com/data-apis/array-api/pull/553)) +- `round`([gh-440](https://github.com/data-apis/array-api/pull/440)) +- `sign`([gh-556](https://github.com/data-apis/array-api/pull/556)) +- `sin`([gh-457](https://github.com/data-apis/array-api/pull/457)) +- `sinh`([gh-456](https://github.com/data-apis/array-api/pull/456)) +- `square`([gh-552](https://github.com/data-apis/array-api/pull/552)) +- `sqrt`([gh-461](https://github.com/data-apis/array-api/pull/461)) +- `subtract`([gh-526](https://github.com/data-apis/array-api/pull/526)) +- `sum`([gh-538](https://github.com/data-apis/array-api/pull/538)) +- `tan`([gh-459](https://github.com/data-apis/array-api/pull/459)) +- `tanh`([gh-458](https://github.com/data-apis/array-api/pull/458)) +- `tensordot`([gh-558](https://github.com/data-apis/array-api/pull/558)) +- `unique_all`([gh-540](https://github.com/data-apis/array-api/pull/540)) +- `unique_counts`([gh-540](https://github.com/data-apis/array-api/pull/540)) +- `unique_inverse`([gh-540](https://github.com/data-apis/array-api/pull/540)) +- `unique_values`([gh-540](https://github.com/data-apis/array-api/pull/540)) +- `vecdot`([gh-512](https://github.com/data-apis/array-api/pull/512)) + +#### Extensions + +> Updates to APIs and requirements included as part of specification extensions. + +- Mechanism by which to access extension APIs ([gh-470](https://github.com/data-apis/array-api/pull/470)) +- `linalg.cross`: add support for broadcasting ([gh-417](https://github.com/data-apis/array-api/pull/417)) +- `linalg.trace`: add support for specifying output array data type ([gh-502](https://github.com/data-apis/array-api/pull/502)) + +##### Complex Number Support + +The following APIs were updated to support arrays having complex floating-point data types: + +- `linalg.cholesky`([gh-443](https://github.com/data-apis/array-api/pull/443)) +- `linalg.cross`([gh-559](https://github.com/data-apis/array-api/pull/559)) +- `linalg.det`([gh-542](https://github.com/data-apis/array-api/pull/542)) +- `linalg.eigh`([gh-543](https://github.com/data-apis/array-api/pull/543)) +- `linalg.eigvalsh`([gh-543](https://github.com/data-apis/array-api/pull/543)) +- `linalg.inv`([gh-547](https://github.com/data-apis/array-api/pull/547)) +- `linalg.matrix_norm`([gh-565](https://github.com/data-apis/array-api/pull/565)) +- `linalg.matrix_power`([gh-549](https://github.com/data-apis/array-api/pull/549)) +- `linalg.matrix_rank`([gh-563](https://github.com/data-apis/array-api/pull/563)) +- `linalg.outer`([gh-560](https://github.com/data-apis/array-api/pull/560)) +- `linalg.pinv`([gh-564](https://github.com/data-apis/array-api/pull/564)) +- `linalg.qr`([gh-548](https://github.com/data-apis/array-api/pull/548)) +- `linalg.slogdet`([gh-567](https://github.com/data-apis/array-api/pull/567)) +- `linalg.solve`([gh-566](https://github.com/data-apis/array-api/pull/566)) +- `linalg.svd`([gh-561](https://github.com/data-apis/array-api/pull/561)) +- `linalg.svdvals`([gh-562](https://github.com/data-apis/array-api/pull/562)) +- `linalg.trace`([gh-541](https://github.com/data-apis/array-api/pull/541)) +- `linalg.vector_norm`([gh-550](https://github.com/data-apis/array-api/pull/550)) + +* * * + +### Additions + +> New APIs and requirements added to the specification. + +#### Data Types + +The following data types were added to the specification: + +- `complex64`: single-precision complex floating-point numbers ([gh-418](https://github.com/data-apis/array-api/pull/418)) +- `complex128`: double-precision complex floating-point numbers ([gh-418](https://github.com/data-apis/array-api/pull/418)) + +To support complex floating-point numbers, the following requirements were added to the specification: + +- Type promotion rules: real-complex and complex-complex data type promotion guidance ([gh-491](https://github.com/data-apis/array-api/pull/491)) +- Guidance for mixing arrays and Python `complex` scalars ([gh-513](https://github.com/data-apis/array-api/pull/513)) +- Guidance for data type variability across devices ([gh-515](https://github.com/data-apis/array-api/pull/515)) +- Guidance for complex number ordering ([gh-527](https://github.com/data-apis/array-api/pull/527)) +- Guidance for complex number equality ([gh-528](https://github.com/data-apis/array-api/pull/528)) +- Guidance for value-based promotion when results are outside of their real domain ([gh-573](https://github.com/data-apis/array-api/pull/573)) + +**note**: conforming implementations must define a default complex floating-point data type. + +#### APIs + +The following APIs were added to the specification: + +- `__array_api_version__`: string representing the version of the array API specification ([gh-480](https://github.com/data-apis/array-api/pull/480)) +- `__complex__`: convert a zero-dimensional array to a Python `complex` object ([gh-497](https://github.com/data-apis/array-api/pull/497)) +- `conj`: return the complex conjugate of a complex number ([gh-446](https://github.com/data-apis/array-api/pull/446)) +- `finfo.dtype`: floating-point data type ([gh-485](https://github.com/data-apis/array-api/pull/485)) +- `iinfo.dtype`: integer data type ([gh-485](https://github.com/data-apis/array-api/pull/485)) +- `imag`: return the imaginary component of a complex number ([gh-496](https://github.com/data-apis/array-api/pull/496)) +- `isdtype`: test whether a provided `dtype` is of a specified data type kind ([gh-503](https://github.com/data-apis/array-api/pull/503)) +- `real`: return the real component of a complex number ([gh-427](https://github.com/data-apis/array-api/pull/427)) +- `take`: return elements of an array along a specified axis ([gh-416](https://github.com/data-apis/array-api/pull/416)) + +#### Extensions + +The following optional extensions were added to the specification: + +- `fft`: Fast Fourier Transforms (FFT) ([gh-189](https://github.com/data-apis/array-api/pull/189)) + + - `fft` + - `ifft` + - `fftn` + - `ifftn` + - `rfft` + - `rfftn` + - `irfft` + - `irfttn` + - `fftfreq` + - `rfftfreq` + - `fftshift` + - `ifftshift` + +* * * + +### Errata + +The following is a list of fixes and points of clarification with regard to the previous version of the specification: + +- Missing `self` parameter for array object properties ([gh-464](https://github.com/data-apis/array-api/pull/464)) +- `__setitem__`: clarify that in-place element-wise operations must not change the shape of the in-place array as a result of broadcasting ([gh-429](https://github.com/data-apis/array-api/pull/429)) +- `full`: missing type annotation for `bool` fill values ([gh-435](https://github.com/data-apis/array-api/pull/435)) +- `full_like`: missing type annotation for `bool` fill values ([gh-435](https://github.com/data-apis/array-api/pull/435)) +- `iinfo`: fix typo in description ([gh-439](https://github.com/data-apis/array-api/pull/439)) +- `linalg.eigh`: fix input data type to allow non-floating-point data types for backward compat in alignment with other `linalg` APIs ([gh-572](https://github.com/data-apis/array-api/pull/572)) +- `linalg.eigvalsh`: fix input data type to allow non-floating-point data types for backward compat in alignment with other `linalg` APIs ([gh-572](https://github.com/data-apis/array-api/pull/572)) +- `linalg.matrix_rank`: fix return data type ([gh-510](https://github.com/data-apis/array-api/pull/510)) +- `linalg.trace`: clarify special cases for floating-point operands and the empty sum ([gh-502](https://github.com/data-apis/array-api/pull/502)) +- `linspace`: conversion of `start` and `stop` should follow type promotion rules ([gh-568](https://github.com/data-apis/array-api/pull/568)) +- `nonzero`: clarify that, for arrays having a boolean data type, non-zero elements are those elements which equal `True` ([gh-441](https://github.com/data-apis/array-api/pull/441)) +- `trunc`: fix description ([gh-511](https://github.com/data-apis/array-api/pull/511)) +- `vecdot`: clarify broadcasting behavior ([gh-417](https://github.com/data-apis/array-api/pull/417) and [gh-473](https://github.com/data-apis/array-api/pull/473)) \ No newline at end of file From ef6690ed7a69ba5ccbea93522c0a7f31cf83784a Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 15 Dec 2022 22:11:47 +0100 Subject: [PATCH 343/551] Clean up duplicate blurbs on function conventions; improve `fft` description --- spec/API_specification/array_object.rst | 9 +-------- spec/API_specification/creation_functions.rst | 4 +--- .../elementwise_functions.rst | 11 ----------- spec/API_specification/index.rst | 12 ++++++++++++ spec/API_specification/indexing_functions.rst | 7 +------ .../linear_algebra_functions.rst | 8 +------- .../manipulation_functions.rst | 5 +---- .../API_specification/searching_functions.rst | 7 +------ spec/API_specification/set_functions.rst | 5 +---- spec/API_specification/sorting_functions.rst | 5 +---- .../statistical_functions.rst | 10 ++-------- spec/API_specification/utility_functions.rst | 10 ++-------- .../fourier_transform_functions.rst | 19 ++++++++++++------- spec/extensions/index.rst | 3 +++ spec/extensions/linear_algebra_functions.rst | 17 +++-------------- 15 files changed, 42 insertions(+), 90 deletions(-) diff --git a/spec/API_specification/array_object.rst b/spec/API_specification/array_object.rst index b45e41987..b15bbdc43 100644 --- a/spec/API_specification/array_object.rst +++ b/spec/API_specification/array_object.rst @@ -5,14 +5,7 @@ Array object Array API specification for array object attributes and methods. -A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods adhering to the following conventions. - -* Positional parameters must be `positional-only `_ parameters. Positional-only parameters have no externally-usable name. When a method 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, methods must support the data types defined in :ref:`data-types`. -* Unless stated otherwise, methods must adhere to the type promotion rules defined in :ref:`type-promotion`. -* Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods. Furthermore, a conforming implementation of the array API standard must support array objects of arbitrary rank ``N`` (i.e., number of dimensions), where ``N`` is greater than or equal to zero. diff --git a/spec/API_specification/creation_functions.rst b/spec/API_specification/creation_functions.rst index 9984ff04c..ff5c06368 100644 --- a/spec/API_specification/creation_functions.rst +++ b/spec/API_specification/creation_functions.rst @@ -3,10 +3,8 @@ Creation Functions Array API specification for creating arrays. -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +A conforming implementation of the array API standard must provide and support the following functions. -- 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. Objects in API -------------- diff --git a/spec/API_specification/elementwise_functions.rst b/spec/API_specification/elementwise_functions.rst index 1f6e818a6..bc21e14b9 100644 --- a/spec/API_specification/elementwise_functions.rst +++ b/spec/API_specification/elementwise_functions.rst @@ -5,17 +5,6 @@ Element-wise Functions Array API specification for element-wise functions. -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`. -- Functions may only be required for a subset of input data type. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. -- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. -- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in :ref:`accuracy`. - Objects in API -------------- diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index bbb96c8a9..1d1d8571d 100644 --- a/spec/API_specification/index.rst +++ b/spec/API_specification/index.rst @@ -3,6 +3,18 @@ API specification ================= +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 when the function signature indicates this (as denoted by `/`). See :ref:`function-and-method-signatures`. +- Optional parameters must be `keyword-only `_ argumentswhen the function signature indicates this (as denoted by `*`). See :ref:`function-and-method-signatures`. +- Broadcasting semantics must follow the semantics defined in :ref:`broadcasting`. +- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. +- Functions may only be required for a subset of input data types. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in :ref:`accuracy`. + + .. toctree:: :caption: API specification :maxdepth: 3 diff --git a/spec/API_specification/indexing_functions.rst b/spec/API_specification/indexing_functions.rst index 264b787ae..aef298566 100644 --- a/spec/API_specification/indexing_functions.rst +++ b/spec/API_specification/indexing_functions.rst @@ -5,13 +5,8 @@ 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. +A conforming implementation of the array API standard must provide and support the following functions. -- 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 -------------- diff --git a/spec/API_specification/linear_algebra_functions.rst b/spec/API_specification/linear_algebra_functions.rst index 9bae18e77..04d36f50a 100644 --- a/spec/API_specification/linear_algebra_functions.rst +++ b/spec/API_specification/linear_algebra_functions.rst @@ -3,14 +3,8 @@ Linear Algebra Functions Array API specification for linear algebra functions. -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +A conforming implementation of the array API standard must provide and support the following functions. -* 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`. -* Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. .. currentmodule:: array_api diff --git a/spec/API_specification/manipulation_functions.rst b/spec/API_specification/manipulation_functions.rst index 86f708a86..4f43f0835 100644 --- a/spec/API_specification/manipulation_functions.rst +++ b/spec/API_specification/manipulation_functions.rst @@ -3,11 +3,8 @@ Manipulation Functions Array API specification for manipulating arrays. -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +A conforming implementation of the array API standard must provide and support the following functions. -- 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. -- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. Objects in API -------------- diff --git a/spec/API_specification/searching_functions.rst b/spec/API_specification/searching_functions.rst index bf09e4c8a..01ab4e82a 100644 --- a/spec/API_specification/searching_functions.rst +++ b/spec/API_specification/searching_functions.rst @@ -5,13 +5,8 @@ Searching Functions Array API specification for functions for searching arrays. -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +A conforming implementation of the array API standard must provide and support the following functions. -- 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 -------------- diff --git a/spec/API_specification/set_functions.rst b/spec/API_specification/set_functions.rst index b7072d100..addf31e1f 100644 --- a/spec/API_specification/set_functions.rst +++ b/spec/API_specification/set_functions.rst @@ -3,11 +3,8 @@ Set Functions Array API specification for creating and operating on sets. -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +A conforming implementation of the array API standard must provide and support the following functions. -- 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. -- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. Objects in API -------------- diff --git a/spec/API_specification/sorting_functions.rst b/spec/API_specification/sorting_functions.rst index 19d7fb439..ad3af8857 100644 --- a/spec/API_specification/sorting_functions.rst +++ b/spec/API_specification/sorting_functions.rst @@ -3,11 +3,8 @@ Sorting Functions Array API specification for sorting functions. -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +A conforming implementation of the array API standard must provide and support the following functions. -* 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. -* Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. .. note:: diff --git a/spec/API_specification/statistical_functions.rst b/spec/API_specification/statistical_functions.rst index 6734506ed..23cd2cb1d 100644 --- a/spec/API_specification/statistical_functions.rst +++ b/spec/API_specification/statistical_functions.rst @@ -3,14 +3,8 @@ Statistical Functions Array API specification for statistical functions. -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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +A conforming implementation of the array API standard must provide and support the following functions. + Objects in API -------------- diff --git a/spec/API_specification/utility_functions.rst b/spec/API_specification/utility_functions.rst index f869b4321..5105fa3df 100644 --- a/spec/API_specification/utility_functions.rst +++ b/spec/API_specification/utility_functions.rst @@ -3,14 +3,8 @@ Utility Functions Array API specification for utility functions. -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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +A conforming implementation of the array API standard must provide and support the following functions. + Objects in API -------------- diff --git a/spec/extensions/fourier_transform_functions.rst b/spec/extensions/fourier_transform_functions.rst index e048dbfad..170ae390b 100644 --- a/spec/extensions/fourier_transform_functions.rst +++ b/spec/extensions/fourier_transform_functions.rst @@ -3,18 +3,23 @@ Fourier transform Functions Array API specification for Fourier transform functions. -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``fft``. + +If implemented, this ``fft`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'fft'): + >>> # Use `xp.fft` -- 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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. Objects in API -------------- +A conforming implementation of this ``fft`` extension must provide and support the following functions. + .. currentmodule:: array_api.fft .. diff --git a/spec/extensions/index.rst b/spec/extensions/index.rst index 706820f3b..30d9cfa90 100644 --- a/spec/extensions/index.rst +++ b/spec/extensions/index.rst @@ -21,6 +21,9 @@ The mechanism through which the extension namespace is made available is up to the implementer, e.g. via a regular submodule that is imported under the ``linalg`` name, or via a module-level ``__getattr__``. +The functions in an extension must adhere to the same conventions as those in +the array API standard. See :ref:`api-specification`. + Extensions ---------- diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/extensions/linear_algebra_functions.rst index c91ce021d..6759b2260 100644 --- a/spec/extensions/linear_algebra_functions.rst +++ b/spec/extensions/linear_algebra_functions.rst @@ -17,20 +17,6 @@ If implemented, this ``linalg`` extension must be retrievable via:: >>> # Use `xp.linalg` -General syntax and semantics rules ----------------------------------- - -.. TODO: get rid of this here, it's duplicated over and over - -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`. -- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. - Design Principles ----------------- @@ -95,6 +81,9 @@ Accordingly, the standardization process affords the opportunity to reduce inter Objects in API -------------- + +A conforming implementation of this ``linalg`` extension must provide and support the following functions. + .. NOTE: please keep the functions in alphabetical order From 816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Dec 2022 02:24:59 -0800 Subject: [PATCH 344/551] Move special cases to notes sections --- .../array_api/elementwise_functions.py | 1094 ++++++++++------- spec/API_specification/array_api/linalg.py | 19 +- .../array_api/statistical_functions.py | 119 +- 3 files changed, 698 insertions(+), 534 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 3a3743ba8..97504c21f 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -16,6 +16,25 @@ def abs(x: array, /) -> array: .. math:: \operatorname{abs}(z) = \sqrt{a^2 + b^2} + .. note:: + For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. + + .. + TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + **Special Cases** For real-valued floating-point operands, @@ -33,22 +52,6 @@ def abs(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. - - .. note:: - For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. - - .. - TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. - - Parameters - ---------- - x: array - input array. Should have a numeric data type. - - Returns - ------- - out: array - an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). """ @@ -58,30 +61,6 @@ def acos(x: array, /) -> array: Each element-wise result is expressed in radians. - **Special cases** - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is greater than ``1``, the result is ``NaN``. - - If ``x_i`` is less than ``-1``, the result is ``NaN``. - - If ``x_i`` is ``1``, the result is ``+0``. - - For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``. - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``. - - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``. - - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``. - - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``. - - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``. - - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``. - - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified). - - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. - - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - .. note:: The principal value of the arc cosine of a complex number :math:`z` is @@ -112,36 +91,39 @@ def acos(x: array, /) -> array: ------- out: array an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - -def acosh(x: array, /) -> array: - r""" - Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. + Notes + ----- **Special cases** For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is less than ``1``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. - If ``x_i`` is ``1``, the result is ``+0``. - - If ``x_i`` is ``+infinity``, the result is ``+infinity``. For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + πj/2``. - - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``. + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``. - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN ± πj/2`` (sign of imaginary component is unspecified). - - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. - - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. - - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. - - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. - - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified). - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + """ + + +def acosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. .. note:: The principal value of the inverse hyperbolic cosine of a complex number :math:`z` is @@ -180,6 +162,33 @@ def acosh(x: array, /) -> array: ------- out: array an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + πj/2``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN ± πj/2`` (sign of imaginary component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. """ @@ -187,6 +196,21 @@ def add(x1: array, x2: array, /) -> array: """ Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** For real-valued floating-point operands, @@ -230,18 +254,6 @@ def add(x1: array, x2: array, /) -> array: - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. - - Parameters - ---------- - x1: array - first input array. Should have a numeric data type. - x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. - - Returns - ------- - out: array - an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. """ @@ -251,18 +263,6 @@ def asin(x: array, /) -> array: Each element-wise result is expressed in radians. - **Special cases** - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is greater than ``1``, the result is ``NaN``. - - If ``x_i`` is less than ``-1``, the result is ``NaN``. - - If ``x_i`` is ``+0``, the result is ``+0``. - - If ``x_i`` is ``-0``, the result is ``-0``. - - For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. - .. note:: The principal value of the arc sine of a complex number :math:`z` is @@ -293,34 +293,27 @@ def asin(x: array, /) -> array: ------- out: array an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - -def asinh(x: array, /) -> array: - r""" - Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. + Notes + ----- **Special cases** For real-valued floating-point operands, - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. - - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - - If ``x_i`` is ``-infinity``, the result is ``-infinity``. - For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + """ - - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. - - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. - - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. - - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. - - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. - - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. - - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). - - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + +def asinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. .. note:: The principal value of the inverse hyperbolic sine of a complex number :math:`z` is @@ -352,14 +345,9 @@ def asinh(x: array, /) -> array: ------- out: array an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - -def atan(x: array, /) -> array: - r""" - Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. - - Each element-wise result is expressed in radians. + Notes + ----- **Special cases** @@ -368,10 +356,28 @@ def atan(x: array, /) -> array: - If ``x_i`` is ``NaN``, the result is ``NaN``. - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. - - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. - - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. - For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + """ + + +def atan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. .. note:: The principal value of the inverse tangent of a complex number :math:`z` is @@ -398,6 +404,9 @@ def atan(x: array, /) -> array: ------- out: array an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- """ @@ -412,6 +421,21 @@ def atan2(x1: array, x2: array, /) -> array: By IEEE 754 convention, the inverse tangent of the quotient ``x1/x2`` is defined for ``x2_i`` equal to positive or negative zero and for either or both of ``x1_i`` and ``x2_i`` equal to positive or negative ``infinity``. + Parameters + ---------- + x1: array + input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. + x2: array + input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** For floating-point operands, @@ -439,19 +463,6 @@ def atan2(x1: array, x2: array, /) -> array: - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. - - Parameters - ---------- - x1: array - input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. - x2: array - input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. - - Returns - ------- - out: array - an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. - """ @@ -459,32 +470,6 @@ def atanh(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element ``x_i`` of the input array ``x``. - **Special cases** - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is less than ``-1``, the result is ``NaN``. - - If ``x_i`` is greater than ``1``, the result is ``NaN``. - - If ``x_i`` is ``-1``, the result is ``-infinity``. - - If ``x_i`` is ``+1``, the result is ``+infinity``. - - If ``x_i`` is ``+0``, the result is ``+0``. - - If ``x_i`` is ``-0``, the result is ``-0``. - - For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - - - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. - - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. - - If ``a`` is ``1`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. - - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. - - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + πj/2``. - - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. - - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. - - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). - - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - .. note:: The principal value of the inverse hyperbolic tangent of a complex number :math:`z` is @@ -515,6 +500,35 @@ def atanh(x: array, /) -> array: ------- out: array an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``+1``, the result is ``+infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``1`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. """ @@ -631,6 +645,19 @@ def ceil(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + **Special cases** - If ``x_i`` is already integer-valued, the result is ``x_i``. @@ -642,16 +669,6 @@ def ceil(x: array, /) -> array: - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. - - Parameters - ---------- - x: array - input array. Should have a real-valued data type. - - Returns - ------- - out: array - an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ @@ -689,18 +706,6 @@ def cos(x: array, /) -> array: Each element ``x_i`` is assumed to be expressed in radians. - **Special cases** - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is ``+0``, the result is ``1``. - - If ``x_i`` is ``-0``, the result is ``1``. - - If ``x_i`` is ``+infinity``, the result is ``NaN``. - - If ``x_i`` is ``-infinity``, the result is ``NaN``. - - For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. - .. note:: The cosine is an entire function on the complex plane and has no branch cuts. @@ -721,6 +726,21 @@ def cos(x: array, /) -> array: ------- out: array an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``NaN``. + - If ``x_i`` is ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. """ @@ -733,6 +753,22 @@ def cosh(x: array, /) -> array: .. math:: \operatorname{cosh}(x) = \frac{e^x + e^{-x}}{2} + .. note:: + The hyperbolic cosine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** .. note:: @@ -765,19 +801,6 @@ def cosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. - - .. note:: - The hyperbolic cosine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. - - Parameters - ---------- - x: array - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. - - Returns - ------- - out: array - an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ @@ -790,6 +813,21 @@ def divide(x1: array, x2: array, /) -> array: Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + Parameters + ---------- + x1: array + dividend input array. Should have a numeric data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** For real-valued floating-point operands, @@ -843,24 +881,27 @@ def divide(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + """ + + +def equal(x1: array, x2: array, /) -> array: + r""" + Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- x1: array - dividend input array. Should have a numeric data type. + first input array. May have any data type. x2: array - divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. Returns ------- out: array - an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - + an array containing the element-wise results. The returned array must have a data type of ``bool``. -def equal(x1: array, x2: array, /) -> array: - r""" - Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + Notes + ----- **Special Cases** @@ -881,24 +922,31 @@ def equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + """ + + +def exp(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. Parameters ---------- - x1: array - first input array. May have any data type. - x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. + x: array + input array. Should have a floating-point data type. Returns ------- out: array - an array containing the element-wise results. The returned array must have a data type of ``bool``. - """ - + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. -def exp(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + Notes + ----- **Special cases** @@ -927,9 +975,18 @@ def exp(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + """ + + +def expm1(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. .. note:: - For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. .. note:: The exponential function is an entire function in the complex plane and has no branch cuts. @@ -942,16 +999,10 @@ def exp(x: array, /) -> array: Returns ------- out: array - an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. -def expm1(x: array, /) -> array: - """ - Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. - - .. note:: - The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + Notes + ----- **Special cases** @@ -980,28 +1031,25 @@ def expm1(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + """ - .. note:: - For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. - .. note:: - The exponential function is an entire function in the complex plane and has no branch cuts. +def floor(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. Parameters ---------- x: array - input array. Should have a floating-point data type. + input array. Should have a real-valued data type. Returns ------- out: array - an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. -def floor(x: array, /) -> array: - """ - Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. + Notes + ----- **Special cases** @@ -1014,25 +1062,66 @@ def floor(x: array, /) -> array: - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def floor_divide(x1: array, x2: array, /) -> array: + r""" + Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + **Special cases** + + .. note:: + Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``\s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + + To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. + + Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. + + This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. Parameters ---------- - x: array - input array. Should have a real-valued data type. + x1: array + dividend input array. Should have a real-valued data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns ------- out: array - an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. - """ - - -def floor_divide(x1: array, x2: array, /) -> array: - r""" - Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. - .. note:: - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + Notes + ----- **Special cases** @@ -1069,18 +1158,6 @@ def floor_divide(x1: array, x2: array, /) -> array: - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - - Parameters - ---------- - x1: array - dividend input array. Should have a real-valued data type. - x2: array - divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. - - Returns - ------- - out: array - an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ @@ -1146,6 +1223,19 @@ def isfinite(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if finite. + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + **Special Cases** For real-valued floating-point operands, @@ -1160,6 +1250,12 @@ def isfinite(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + """ + + +def isinf(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. Parameters ---------- @@ -1170,12 +1266,9 @@ def isfinite(x: array, /) -> array: ------- out: array an array containing test results. The returned array must have a data type of ``bool``. - """ - -def isinf(x: array, /) -> array: - """ - Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. + Notes + ----- **Special Cases** @@ -1189,6 +1282,12 @@ def isinf(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - In the remaining cases, the result is ``False``. + """ + + +def isnan(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. Parameters ---------- @@ -1198,13 +1297,10 @@ def isinf(x: array, /) -> array: Returns ------- out: array - an array containing test results. The returned array must have a data type of ``bool``. - """ - + an array containing test results. The returned array should have a data type of ``bool``. -def isnan(x: array, /) -> array: - """ - Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. + Notes + ----- **Special Cases** @@ -1217,16 +1313,6 @@ def isnan(x: array, /) -> array: - If ``a`` or ``b`` is ``NaN``, the result is ``True``. - In the remaining cases, the result is ``False``. - - Parameters - ---------- - x: array - input array. Should have a numeric data type. - - Returns - ------- - out: array - an array containing test results. The returned array should have a data type of ``bool``. """ @@ -1276,6 +1362,34 @@ def log(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm for each element ``x_i`` of the input array ``x``. + .. note:: + The natural logarithm of a complex number :math:`z` with polar coordinates :math:`(r,\theta)` equals :math:`\ln r + (\theta + 2n\pi)j` with principal value :math:`\ln r + \theta j`. + + .. note:: + For complex floating-point operands, ``log(conj(x))`` must equal ``conj(log(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** For real-valued floating-point operands, @@ -1300,12 +1414,18 @@ def log(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + """ + + +def log1p(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. .. note:: - The natural logarithm of a complex number :math:`z` with polar coordinates :math:`(r,\theta)` equals :math:`\ln r + (\theta + 2n\pi)j` with principal value :math:`\ln r + \theta j`. + The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. .. note:: - For complex floating-point operands, ``log(conj(x))`` must equal ``conj(log(x))``. + For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. .. note:: By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. @@ -1324,16 +1444,10 @@ def log(x: array, /) -> array: Returns ------- out: array - an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - - -def log1p(x: array, /) -> array: - r""" - Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - .. note:: - The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + Notes + ----- **Special cases** @@ -1359,18 +1473,15 @@ def log1p(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + """ - .. note:: - For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. - - .. note:: - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. - - The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. - Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. +def log2(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + .. note:: + For complex floating-point operands, ``log2(conj(x))`` must equal ``conj(log2(x))``. Parameters ---------- @@ -1380,13 +1491,10 @@ def log1p(x: array, /) -> array: Returns ------- out: array - an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. -def log2(x: array, /) -> array: - r""" - Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. + Notes + ----- **Special cases** @@ -1404,9 +1512,15 @@ def log2(x: array, /) -> array: \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + """ + + +def log10(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. .. note:: - For complex floating-point operands, ``log2(conj(x))`` must equal ``conj(log2(x))``. + For complex floating-point operands, ``log10(conj(x))`` must equal ``conj(log10(x))``. Parameters ---------- @@ -1416,13 +1530,10 @@ def log2(x: array, /) -> array: Returns ------- out: array - an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. -def log10(x: array, /) -> array: - r""" - Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. + Notes + ----- **Special cases** @@ -1440,19 +1551,6 @@ def log10(x: array, /) -> array: \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. - - .. note:: - For complex floating-point operands, ``log10(conj(x))`` must equal ``conj(log10(x))``. - - Parameters - ---------- - x: array - input array. Should have a floating-point data type. - - Returns - ------- - out: array - an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ @@ -1460,14 +1558,6 @@ def logaddexp(x1: array, x2: array, /) -> array: """ Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - **Special cases** - - For floating-point operands, - - - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. - - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. - Parameters ---------- x1: array @@ -1479,6 +1569,17 @@ def logaddexp(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. """ @@ -1568,6 +1669,24 @@ def multiply(x1: array, x2: array, /) -> array: r""" Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** For real-valued floating-point operands, @@ -1608,21 +1727,6 @@ def multiply(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. - - .. note:: - Floating-point multiplication is not always associative due to finite precision. - - Parameters - ---------- - x1: array - first input array. Should have a numeric data type. - x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. - - Returns - ------- - out: array - an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. """ @@ -1652,6 +1756,21 @@ def not_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + Parameters + ---------- + x1: array + first input array. May have any data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + **Special Cases** For real-valued floating-point operands, @@ -1669,18 +1788,6 @@ def not_equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. - - Parameters - ---------- - x1: array - first input array. May have any data type. - x2: array - second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). - - Returns - ------- - out: array - an array containing the element-wise results. The returned array must have a data type of ``bool``. """ @@ -1707,7 +1814,29 @@ def pow(x1: array, x2: array, /) -> array: .. note:: If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x1: array + first input array whose elements correspond to the exponentiation base. Should have a numeric data type. + x2: array + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- **Special cases** @@ -1742,25 +1871,6 @@ def pow(x1: array, x2: array, /) -> array: .. note:: Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. - - .. note:: - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. - - The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). - - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). - - Parameters - ---------- - x1: array - first input array whose elements correspond to the exponentiation base. Should have a numeric data type. - x2: array - second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. - - Returns - ------- - out: array - an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ @@ -1790,6 +1900,21 @@ def remainder(x1: array, x2: array, /) -> array: .. note:: For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + Parameters + ---------- + x1: array + dividend input array. Should have a real-valued data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** .. note:: @@ -1817,18 +1942,6 @@ def remainder(x1: array, x2: array, /) -> array: - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) - In the remaining cases, the result must match that of the Python ``%`` operator. - - Parameters - ---------- - x1: array - dividend input array. Should have a real-valued data type. - x2: array - divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. - - Returns - ------- - out: array - an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. """ @@ -1841,6 +1954,19 @@ def round(x: array, /) -> array: Rounded real and imaginary components must be equal to their equivalent rounded real-valued floating-point counterparts (i.e., for complex-valued ``x``, ``real(round(x))`` must equal ``round(real(x)))`` and ``imag(round(x))`` must equal ``round(imag(x))``). + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + **Special cases** .. note:: @@ -1856,16 +1982,6 @@ def round(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. - - Parameters - ---------- - x: array - input array. Should have a numeric data type. - - Returns - ------- - out: array - an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ @@ -1883,6 +1999,19 @@ def sign(x: array, /) -> array: where :math:`|x_i|` is the absolute value of :math:`x_i`. + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + **Special cases** For real-valued operands, @@ -1897,16 +2026,6 @@ def sign(x: array, /) -> array: - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). - - Parameters - ---------- - x: array - input array. Should have a numeric data type. - - Returns - ------- - out: array - an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. """ @@ -1916,17 +2035,6 @@ def sin(x: array, /) -> array: Each element ``x_i`` is assumed to be expressed in radians. - **Special cases** - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is ``+0``, the result is ``+0``. - - If ``x_i`` is ``-0``, the result is ``-0``. - - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. - - For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. - .. note:: The sine is an entire function on the complex plane and has no branch cuts. @@ -1947,6 +2055,20 @@ def sin(x: array, /) -> array: ------- out: array an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. """ @@ -1959,6 +2081,22 @@ def sinh(x: array, /) -> array: .. math:: \operatorname{sinh}(x) = \frac{e^x - e^{-x}}{2} + .. note:: + The hyperbolic sine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** .. note:: @@ -1991,19 +2129,6 @@ def sinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. - - .. note:: - The hyperbolic sine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. - - Parameters - ---------- - x: array - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. - - Returns - ------- - out: array - an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ @@ -2016,10 +2141,6 @@ def square(x: array, /) -> array: .. math:: x_i^2 = x_i \cdot x_i - **Special cases** - - For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). - Parameters ---------- x: array @@ -2029,6 +2150,13 @@ def square(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). """ @@ -2039,28 +2167,6 @@ def sqrt(x: array, /) -> array: .. note:: After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). - **Special cases** - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is less than ``0``, the result is ``NaN``. - - If ``x_i`` is ``+0``, the result is ``+0``. - - If ``x_i`` is ``-0``, the result is ``-0``. - - If ``x_i`` is ``+infinity``, the result is ``+infinity``. - - For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - - - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. - - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. - - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. - - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. - - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). - - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. - - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. - - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. - .. note:: For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. @@ -2082,6 +2188,31 @@ def sqrt(x: array, /) -> array: ------- out: array an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. """ @@ -2111,17 +2242,6 @@ def tan(x: array, /) -> array: Each element ``x_i`` is assumed to be expressed in radians. - **Special cases** - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is ``+0``, the result is ``+0``. - - If ``x_i`` is ``-0``, the result is ``-0``. - - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. - - For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. - .. note:: Tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the real component and has first order poles along the real line at coordinates :math:`(\pi (\frac{1}{2} + n), 0)`. However, IEEE 754 binary floating-point representation cannot represent the value :math:`\pi / 2` exactly, and, thus, no argument value is possible for which a pole error occurs. @@ -2142,6 +2262,20 @@ def tan(x: array, /) -> array: ------- out: array an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. """ @@ -2156,6 +2290,22 @@ def tanh(x: array, /) -> array: where :math:`\operatorname{sinh}(x)` is the hyperbolic sine and :math:`\operatorname{cosh}(x)` is the hyperbolic cosine. + .. note:: + The hyperbolic tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the imaginary component and has first order poles along the imaginary line at coordinates :math:`(0, \pi (\frac{1}{2} + n))`. However, IEEE 754 binary floating-point representation cannot represent :math:`\pi / 2` exactly, and, thus, no argument value is possible such that a pole error occurs. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + **Special cases** .. note:: @@ -2190,25 +2340,25 @@ def tanh(x: array, /) -> array: For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + """ - .. note:: - The hyperbolic tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the imaginary component and has first order poles along the imaginary line at coordinates :math:`(0, \pi (\frac{1}{2} + n))`. However, IEEE 754 binary floating-point representation cannot represent :math:`\pi / 2` exactly, and, thus, no argument value is possible such that a pole error occurs. + +def trunc(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. Parameters ---------- x: array - input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + input array. Should have a real-valued data type. Returns ------- out: array - an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. - """ - + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. -def trunc(x: array, /) -> array: - """ - Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. + Notes + ----- **Special cases** @@ -2221,16 +2371,6 @@ def trunc(x: array, /) -> array: - If ``x_i`` is ``+0``, the result is ``+0``. - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. - - Parameters - ---------- - x: array - input array. Should have a real-valued data type. - - Returns - ------- - out: array - an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ diff --git a/spec/API_specification/array_api/linalg.py b/spec/API_specification/array_api/linalg.py index 65e25bc5e..b040251dd 100644 --- a/spec/API_specification/array_api/linalg.py +++ b/spec/API_specification/array_api/linalg.py @@ -606,14 +606,6 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr """ Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. - **Special Cases** - - Let ``N`` equal the number of elements over which to compute the sum. - - - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). - - For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. - Parameters ---------- x: array @@ -650,6 +642,17 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. """ diff --git a/spec/API_specification/array_api/statistical_functions.py b/spec/API_specification/array_api/statistical_functions.py index 24ef810af..787faeeb9 100644 --- a/spec/API_specification/array_api/statistical_functions.py +++ b/spec/API_specification/array_api/statistical_functions.py @@ -17,12 +17,6 @@ def max( .. note:: For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - **Special Cases** - - For floating-point operands, - - - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). - Parameters ---------- x: array @@ -36,6 +30,15 @@ def max( ------- out: array if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). """ @@ -49,13 +52,6 @@ def mean( """ Calculates the arithmetic mean of the input array ``x``. - **Special Cases** - - Let ``N`` equal the number of elements over which to compute the arithmetic mean. - - - If ``N`` is ``0``, the arithmetic mean is ``NaN``. - - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). - Parameters ---------- x: array @@ -72,6 +68,16 @@ def mean( .. note:: While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the arithmetic mean. + + - If ``N`` is ``0``, the arithmetic mean is ``NaN``. + - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). """ @@ -91,12 +97,6 @@ def min( .. note:: For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - **Special Cases** - - For floating-point operands, - - - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). - Parameters ---------- x: array @@ -110,6 +110,15 @@ def min( ------- out: array if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). """ @@ -124,14 +133,6 @@ def prod( """ Calculates the product of input array ``x`` elements. - **Special Cases** - - Let ``N`` equal the number of elements over which to compute the product. - - - If ``N`` is ``0``, the product is `1` (i.e., the empty product). - - For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. - Parameters ---------- x: array @@ -159,6 +160,17 @@ def prod( ------- out: array if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the product. + + - If ``N`` is ``0``, the product is `1` (i.e., the empty product). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. """ @@ -173,13 +185,6 @@ def std( """ Calculates the standard deviation of the input array ``x``. - **Special Cases** - - Let ``N`` equal the number of elements over which to compute the standard deviation. - - - If ``N - correction`` is less than or equal to ``0``, the standard deviation is ``NaN``. - - If ``x_i`` is ``NaN``, the standard deviation is ``NaN`` (i.e., ``NaN`` values propagate). - Parameters ---------- x: array @@ -198,6 +203,16 @@ def std( .. note:: While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the standard deviation. + + - If ``N - correction`` is less than or equal to ``0``, the standard deviation is ``NaN``. + - If ``x_i`` is ``NaN``, the standard deviation is ``NaN`` (i.e., ``NaN`` values propagate). """ @@ -212,14 +227,6 @@ def sum( """ Calculates the sum of the input array ``x``. - **Special Cases** - - Let ``N`` equal the number of elements over which to compute the sum. - - - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). - - For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. - Parameters ---------- x: array @@ -247,6 +254,17 @@ def sum( ------- out: array if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. """ @@ -261,13 +279,6 @@ def var( """ Calculates the variance of the input array ``x``. - **Special Cases** - - Let ``N`` equal the number of elements over which to compute the variance. - - - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. - - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). - Parameters ---------- x: array @@ -287,6 +298,16 @@ def var( .. note:: While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the variance. + + - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. + - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). """ From 22301d7378e494d7035f81fa0d08ffd8a7806a1f Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Dec 2022 02:25:41 -0800 Subject: [PATCH 345/551] Add revision to list of commits to ignore --- .git-blame-ignore-revs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 8fd251e32..3ea0eb1b5 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,5 @@ # Migrate code style to Black 162034b12711dad54589c5dc9e75942695a7957f + +# Move special cases to notes sections +816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 \ No newline at end of file From 7f4d85b15e04cce8ae94f1fab68ee6e0e310c0c0 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Dec 2022 02:36:47 -0800 Subject: [PATCH 346/551] Remove special cases and rely on function API equality statement --- .../array_api/array_object.py | 338 +----------------- 1 file changed, 9 insertions(+), 329 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 7c92800d0..9b8d11bfd 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -126,32 +126,6 @@ def __abs__(self: array, /) -> array: .. note:: For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. - **Special cases** - - Let ``self`` equal ``x``. - - For real-valued floating-point operands, - - - If ``x_i`` is ``NaN``, the result is ``NaN``. - - If ``x_i`` is ``-0``, the result is ``+0``. - - If ``x_i`` is ``-infinity``, the result is ``+infinity``. - - For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and - - - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``. - - If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``. - - If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``. - - If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``. - - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. - - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. - - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. - - .. note:: - For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. - - .. - TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. - Parameters ---------- self: array @@ -164,59 +138,13 @@ def __abs__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. """ def __add__(self: array, other: Union[int, float, array], /) -> array: """ Calculates the sum for each element of an array instance with the respective element of the array ``other``. - **Special cases** - - Let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - For real-valued floating-point operands, - - - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``NaN``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``-infinity``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is ``+infinity``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is ``-infinity``. - - If ``x1_i`` is a finite number and ``x2_i`` is ``+infinity``, the result is ``+infinity``. - - If ``x1_i`` is a finite number and ``x2_i`` is ``-infinity``, the result is ``-infinity``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is ``-0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``+0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. - - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is a nonzero finite number, the result is ``x2_i``. - - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. - - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. - - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. - - .. note:: - Floating-point addition is a commutative operation, but not always associative. - - For complex floating-point operands, addition is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, - - +------------+------------+------------+----------------+ - | | c | dj | c + dj | - +============+============+============+================+ - | **a** | a + c | a + dj | (a+c) + dj | - +------------+------------+------------+----------------+ - | **bj** | c + bj | (b+d)j | c + (b+d)j | - +------------+------------+------------+----------------+ - | **a + bj** | (a+c) + bj | a + (b+d)j | (a+c) + (b+d)j | - +------------+------------+------------+----------------+ - - For complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. For example, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and - - - If ``a`` is ``-0`` and ``c`` is ``-0``, the real component of the result is ``-0``. - - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. - - Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. - Parameters ---------- self: array @@ -231,7 +159,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -424,28 +352,6 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. - **Special Cases** - - Let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - For real-valued floating-point operands, - - - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``False``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. - - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` equals ``x2_i``, the result is ``True``. - - In the remaining cases, the result is ``False``. - - For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and - - - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``False``. - - In the remaining cases, the result is the logical AND of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a == c AND b == d``). - - .. note:: - For discussion of complex number equality, see :ref:`complex-numbers`. - Parameters ---------- self: array @@ -460,7 +366,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. """ def __float__(self: array, /) -> float: @@ -495,42 +401,6 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: .. note:: For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - **Special cases** - - .. note:: - Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. - - To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. - - Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. - - This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. - - For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. - - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. - - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to ``+infinity``) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - Parameters ---------- self: array @@ -545,7 +415,7 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. """ def __ge__(self: array, other: Union[int, float, array], /) -> array: @@ -810,34 +680,6 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - **Special Cases** - - .. note:: - In general, this method is **not** recommended for floating-point operands as semantics do not follow IEEE 754. That this method is specified to accept floating-point operands is primarily for reasons of backward compatibility. - - For floating-point operands, let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. - - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``-0``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x2_i``. (**note**: this result matches Python behavior.) - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) - - In the remaining cases, the result must match that of the Python ``%`` operator. - Parameters ---------- self: array @@ -852,56 +694,13 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ def __mul__(self: array, other: Union[int, float, array], /) -> array: r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. - **Special cases** - - Let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - For real-valued floating-point operands, - - - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. - - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. - - If ``x1_i`` and ``x2_i`` have the same mathematical sign, the result has a positive mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. - - If ``x1_i`` and ``x2_i`` have different mathematical signs, the result has a negative mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. - - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. - - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. - - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. - - In the remaining cases, where neither ``infinity`` nor `NaN` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. - - For complex floating-point operands, multiplication is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, - - +------------+----------------+-----------------+--------------------------+ - | | c | dj | c + dj | - +============+================+=================+==========================+ - | **a** | a * c | (a*d)j | (a*c) + (a*d)j | - +------------+----------------+-----------------+--------------------------+ - | **bj** | (b*c)j | -(b*d) | -(b*d) + (b*c)j | - +------------+----------------+-----------------+--------------------------+ - | **a + bj** | (a*c) + (b*c)j | -(b*d) + (a*d)j | special rules | - +------------+----------------+-----------------+--------------------------+ - - In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. - - When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), multiplication of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number multiplication - - .. math:: - (a + bj) \cdot (c + dj) = (ac - bd) + (bc + ad)j - - When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, - - - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. - - In the remaining cases, the result is implementation dependent. - - .. note:: - For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. - .. note:: Floating-point multiplication is not always associative due to finite precision. @@ -919,33 +718,13 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. - **Special Cases** - - Let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - For real-valued floating-point operands, - - - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``True``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. - - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` does not equal ``x2_i``, the result is ``True``. - - In the remaining cases, the result is ``False``. - - For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and - - - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``True``. - - In the remaining cases, the result is the logical OR of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a != c OR b != d``). - - .. note:: - For discussion of complex number equality, see :ref:`complex-numbers`. - Parameters ---------- self: array @@ -960,7 +739,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. """ def __neg__(self: array, /) -> array: @@ -1037,49 +816,6 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - **Special cases** - - Let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - For real-valued floating-point operands, - - - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. - - If ``x2_i`` is ``-0``, the result is `1`, even if ``x1_i`` is ``NaN``. - - If ``x1_i`` is ``NaN`` and ``x2_i`` is not equal to ``0``, the result is ``NaN``. - - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. - - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+0``. - - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``+infinity``, the result is ``1``. - - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``-infinity``, the result is ``1``. - - If ``x1_i`` is ``1`` and ``x2_i`` is not ``NaN``, the result is ``1``. - - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+0``. - - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+infinity``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is greater than ``0``, the result is ``+infinity``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is less than ``0``, the result is ``+0``. - - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. - - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. - - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. - - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``+infinity``. - - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. - - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. - - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. - - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. - - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. - - For complex floating-point operands, special cases should be handled as if the operation is implemented as ``exp(x2*log(x1))``. - - .. note:: - Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. - - .. note:: - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. - - The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(other*log(self))``, exponentiation has the same branch cut for ``self`` as the natural logarithm (see :func:`~array_api.log`). - - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). - Parameters ---------- self: array @@ -1094,7 +830,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -1180,62 +916,6 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. - **Special cases** - - Let ``self`` equal ``x1`` and ``other`` equal ``x2``. - - For floating-point operands, - - - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is `NaN`. - - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. - - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - - For complex floating-point operands, division is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, - - +------------+----------------+-----------------+--------------------------+ - | | c | dj | c + dj | - +============+================+=================+==========================+ - | **a** | a / c | -(a/d)j | special rules | - +------------+----------------+-----------------+--------------------------+ - | **bj** | (b/c)j | b/d | special rules | - +------------+----------------+-----------------+--------------------------+ - | **a + bj** | (a/c) + (b/c)j | b/d - (a/d)j | special rules | - +------------+----------------+-----------------+--------------------------+ - - In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. - - When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division - - .. math:: - \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} - - When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, - - - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. - - In the remaining cases, the result is implementation dependent. - - .. note:: - For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. - Parameters ---------- self: array @@ -1250,7 +930,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: From 0a2fa71a32b924cc92718db29910a6cbbc5e9341 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Dec 2022 02:39:22 -0800 Subject: [PATCH 347/551] Move special cases to notes section --- .../array_api/array_object.py | 79 +++++++++++-------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/spec/API_specification/array_api/array_object.py b/spec/API_specification/array_api/array_object.py index 9b8d11bfd..89e5ee1c3 100644 --- a/spec/API_specification/array_api/array_object.py +++ b/spec/API_specification/array_api/array_object.py @@ -206,6 +206,19 @@ def __bool__(self: array, /) -> bool: """ Converts a zero-dimensional array to a Python ``bool`` object. + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: bool + a Python ``bool`` object representing the single element of the array. + + Notes + ----- + **Special cases** For real-valued floating-point operands, @@ -215,6 +228,11 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + """ + + def __complex__(self: array, /) -> complex: + """ + Converts a zero-dimensional array to a Python ``complex`` object. Parameters ---------- @@ -223,13 +241,11 @@ def __bool__(self: array, /) -> bool: Returns ------- - out: bool - a Python ``bool`` object representing the single element of the array. - """ + out: complex + a Python ``complex`` object representing the single element of the array instance. - def __complex__(self: array, /) -> complex: - """ - Converts a zero-dimensional array to a Python ``complex`` object. + Notes + ----- **Special cases** @@ -244,16 +260,6 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. - If ``self`` is a finite number, the result is ``self + 0j``. - - Parameters - ---------- - self: array - zero-dimensional array instance. - - Returns - ------- - out: complex - a Python ``complex`` object representing the single element of the array instance. """ def __dlpack__( @@ -376,13 +382,6 @@ def __float__(self: array, /) -> float: .. note:: Casting integer values outside the representable bounds of Python's float type is not specified and is implementation-dependent. - **Special cases** - - For boolean operands, - - - If ``self`` is ``True``, the result is ``1``. - - If ``self`` is ``False``, the result is ``0``. - Parameters ---------- self: array @@ -392,6 +391,16 @@ def __float__(self: array, /) -> float: ------- out: float a Python ``float`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. """ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: @@ -511,6 +520,19 @@ def __int__(self: array, /) -> int: """ Converts a zero-dimensional array to a Python ``int`` object. + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + **Special cases** For boolean operands, @@ -523,17 +545,6 @@ def __int__(self: array, /) -> int: - If ``self`` is a finite number, the result is the integer part of ``self``. - If ``self`` is ``-0``, the result is ``0``. - Parameters - ---------- - self: array - zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. - - Returns - ------- - out: int - a Python ``int`` object representing the single element of the array instance. - - **Raises** For floating-point operands, From 6789626dbe87317d8328f8558c6e0b801bf8375f Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Dec 2022 02:40:01 -0800 Subject: [PATCH 348/551] Add revision moving special cases to notes sections --- .git-blame-ignore-revs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 3ea0eb1b5..3b0c752ab 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -2,4 +2,7 @@ 162034b12711dad54589c5dc9e75942695a7957f # Move special cases to notes sections -816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 \ No newline at end of file +816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 + +# Move array object method special cases to notes sections +0a2fa71a32b924cc92718db29910a6cbbc5e9341 \ No newline at end of file From 931144e7d7d5c8b23393aa730ef28962a35b113b Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Dec 2022 11:20:42 -0800 Subject: [PATCH 349/551] Fix duplicate content and missing special cases --- .../array_api/elementwise_functions.py | 48 +++++-------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 97504c21f..3fce08c94 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -407,6 +407,18 @@ def atan(x: array, /) -> array: Notes ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. """ @@ -1072,42 +1084,6 @@ def floor_divide(x1: array, x2: array, /) -> array: .. note:: For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - **Special cases** - - .. note:: - Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``\s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. - - To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. - - Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. - - This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. - - For floating-point operands, - - - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. - - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. - - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. - - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. - - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. - - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. - - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) - - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. - - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. - Parameters ---------- x1: array From bd405efd3cb3c1afa9618c91ed265c8b978ee1ad Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 19 Dec 2022 11:26:47 -0800 Subject: [PATCH 350/551] Add commit --- .git-blame-ignore-revs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 3b0c752ab..64a94ebe7 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -3,6 +3,5 @@ # Move special cases to notes sections 816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 - -# Move array object method special cases to notes sections -0a2fa71a32b924cc92718db29910a6cbbc5e9341 \ No newline at end of file +0a2fa71a32b924cc92718db29910a6cbbc5e9341 +931144e7d7d5c8b23393aa730ef28962a35b113b \ No newline at end of file From b0edf0cd1a0221e95b3acb3e98fb01c28ae09d55 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Dec 2022 20:32:58 +0100 Subject: [PATCH 351/551] Add Changelog and License to the rendered website, update copyright year (#577) This is a follow-up to gh-574 --- LICENSE | 4 ++-- spec/changelog.rst | 5 +++++ spec/conf.py | 4 ++-- spec/index.rst | 7 +++++++ spec/license.rst | 9 +++++++++ 5 files changed, 25 insertions(+), 4 deletions(-) create mode 100644 spec/changelog.rst create mode 100644 spec/license.rst diff --git a/LICENSE b/LICENSE index 0d5280506..e861ffccf 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020 Consortium for Python Data API Standards contributors +Copyright (c) 2020-2022 Consortium for Python Data API Standards contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/spec/changelog.rst b/spec/changelog.rst new file mode 100644 index 000000000..e0993307d --- /dev/null +++ b/spec/changelog.rst @@ -0,0 +1,5 @@ +Changelog per API standard version +================================== + +.. include:: ../CHANGELOG.md + :parser: myst_parser.sphinx_ diff --git a/spec/conf.py b/spec/conf.py index 14ccf872b..9c01adabd 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -18,11 +18,11 @@ # -- Project information ----------------------------------------------------- project = 'Python array API standard' -copyright = '2020, Consortium for Python Data API Standards' +copyright = '2020-2022, Consortium for Python Data API Standards' author = 'Consortium for Python Data API Standards' # The full version, including alpha/beta/rc tags -release = '2022.05-DRAFT' +release = '2022.12-DRAFT' # -- General configuration --------------------------------------------------- diff --git a/spec/index.rst b/spec/index.rst index 706c2f5e6..3e51cc68e 100644 --- a/spec/index.rst +++ b/spec/index.rst @@ -28,3 +28,10 @@ Contents usage_data verification_test_suite benchmark_suite + +.. toctree:: + :caption: Other + :maxdepth: 1 + + changelog + license diff --git a/spec/license.rst b/spec/license.rst new file mode 100644 index 000000000..8d4b6d1fd --- /dev/null +++ b/spec/license.rst @@ -0,0 +1,9 @@ +License +======= + +All content on this website and the corresponding +`GitHub repository `__ is licensed +under the following license: + + .. include:: ../LICENSE + :parser: myst_parser.sphinx_ From 3e0efdfe36f2f27bb9b522aca491386b2b966d75 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Dec 2022 22:11:34 +0100 Subject: [PATCH 352/551] Update spec/API_specification/index.rst Co-authored-by: Athan --- spec/API_specification/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index 1d1d8571d..9689fa5c7 100644 --- a/spec/API_specification/index.rst +++ b/spec/API_specification/index.rst @@ -3,7 +3,7 @@ API specification ================= -A conforming implementation of the array API standard must provide and support the following functions adhering to the following conventions. +A conforming implementation of the array API standard must provide and support the APIs and behavior detailed in this specification while adhering to the following conventions. - Positional parameters must be `positional-only `_ parameters when the function signature indicates this (as denoted by `/`). See :ref:`function-and-method-signatures`. - Optional parameters must be `keyword-only `_ argumentswhen the function signature indicates this (as denoted by `*`). See :ref:`function-and-method-signatures`. From 00a9793442bb62e2c05d9866e1cec23384edd25e Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 19 Dec 2022 22:12:10 +0100 Subject: [PATCH 353/551] Apply suggestions from code review Co-authored-by: Athan --- spec/API_specification/index.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/API_specification/index.rst b/spec/API_specification/index.rst index 9689fa5c7..603131ab9 100644 --- a/spec/API_specification/index.rst +++ b/spec/API_specification/index.rst @@ -5,8 +5,8 @@ API specification A conforming implementation of the array API standard must provide and support the APIs and behavior detailed in this specification while adhering to the following conventions. -- Positional parameters must be `positional-only `_ parameters when the function signature indicates this (as denoted by `/`). See :ref:`function-and-method-signatures`. -- Optional parameters must be `keyword-only `_ argumentswhen the function signature indicates this (as denoted by `*`). See :ref:`function-and-method-signatures`. +- When a function signature includes a `/`, positional parameters must be `positional-only `_ parameters. See :ref:`function-and-method-signatures`. +- When a function signature includes a `*`, optional parameters must be `keyword-only `_ arguments. See :ref:`function-and-method-signatures`. - Broadcasting semantics must follow the semantics defined in :ref:`broadcasting`. - Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. - Functions may only be required for a subset of input data types. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. From b40ed890bc0d84e7b0f1884dfc7fc438de2b6659 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 21 Dec 2022 06:56:45 -0800 Subject: [PATCH 354/551] Update to indicate that branch cuts follow C99 (#579) --- .../array_api/elementwise_functions.py | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/spec/API_specification/array_api/elementwise_functions.py b/spec/API_specification/array_api/elementwise_functions.py index 3fce08c94..6b2a46e24 100644 --- a/spec/API_specification/array_api/elementwise_functions.py +++ b/spec/API_specification/array_api/elementwise_functions.py @@ -80,7 +80,7 @@ def acos(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \pi]` along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -151,7 +151,7 @@ def acosh(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse hyperbolic cosine in the interval :math:`[0, \infty)` along the real axis and in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -282,7 +282,7 @@ def asin(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse sine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -334,7 +334,7 @@ def asinh(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse hyperbolic sine in the range of a strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -393,7 +393,7 @@ def atan(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse tangent in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -501,7 +501,7 @@ def atanh(x: array, /) -> array: Accordingly, for complex arguments, the function returns the inverse hyperbolic tangent in the range of a half-strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -1351,7 +1351,7 @@ def log(x: array, /) -> array: Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -1410,7 +1410,7 @@ def log1p(x: array, /) -> array: Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -1797,7 +1797,7 @@ def pow(x1: array, x2: array, /) -> array: The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- @@ -2153,7 +2153,7 @@ def sqrt(x: array, /) -> array: Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). - *Note: branch cuts have provisional status* (see :ref:`branch-cuts`). + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). Parameters ---------- From 0b49524419116742eee3bdc1475e0bc705f7ee75 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 21 Dec 2022 12:24:03 -0800 Subject: [PATCH 355/551] Update release version --- spec/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/conf.py b/spec/conf.py index 9c01adabd..f4aba0e18 100644 --- a/spec/conf.py +++ b/spec/conf.py @@ -22,7 +22,7 @@ author = 'Consortium for Python Data API Standards' # The full version, including alpha/beta/rc tags -release = '2022.12-DRAFT' +release = '2022.12' # -- General configuration --------------------------------------------------- From dcc5a08c92d7752fbcd78cd8a39d5851a77ee718 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 3 Jan 2023 12:30:33 +0000 Subject: [PATCH 356/551] Rudimentary pkg and folder-per-persion docs --- spec/{ => 2022.12}/API_specification/array_object.rst | 0 spec/{ => 2022.12}/API_specification/broadcasting.rst | 0 spec/{ => 2022.12}/API_specification/constants.rst | 0 spec/{ => 2022.12}/API_specification/creation_functions.rst | 0 spec/{ => 2022.12}/API_specification/data_type_functions.rst | 0 spec/{ => 2022.12}/API_specification/data_types.rst | 0 spec/{ => 2022.12}/API_specification/elementwise_functions.rst | 0 .../API_specification/function_and_method_signatures.rst | 0 spec/{ => 2022.12}/API_specification/index.rst | 0 spec/{ => 2022.12}/API_specification/indexing.rst | 0 spec/{ => 2022.12}/API_specification/indexing_functions.rst | 0 spec/{ => 2022.12}/API_specification/linear_algebra_functions.rst | 0 spec/{ => 2022.12}/API_specification/manipulation_functions.rst | 0 spec/{ => 2022.12}/API_specification/searching_functions.rst | 0 spec/{ => 2022.12}/API_specification/set_functions.rst | 0 spec/{ => 2022.12}/API_specification/sorting_functions.rst | 0 spec/{ => 2022.12}/API_specification/statistical_functions.rst | 0 spec/{ => 2022.12}/API_specification/type_promotion.rst | 0 spec/{ => 2022.12}/API_specification/utility_functions.rst | 0 spec/{ => 2022.12}/API_specification/version.rst | 0 spec/{ => 2022.12}/assumptions.md | 0 spec/{ => 2022.12}/benchmark_suite.md | 0 spec/{ => 2022.12}/changelog.rst | 0 spec/{ => 2022.12}/design_topics/C_API.rst | 0 spec/{ => 2022.12}/design_topics/accuracy.rst | 0 spec/{ => 2022.12}/design_topics/complex_numbers.rst | 0 spec/{ => 2022.12}/design_topics/copies_views_and_mutation.rst | 0 spec/{ => 2022.12}/design_topics/data_dependent_output_shapes.rst | 0 spec/{ => 2022.12}/design_topics/data_interchange.rst | 0 spec/{ => 2022.12}/design_topics/device_support.rst | 0 spec/{ => 2022.12}/design_topics/index.rst | 0 spec/{ => 2022.12}/design_topics/parallelism.rst | 0 spec/{ => 2022.12}/design_topics/static_typing.rst | 0 spec/{ => 2022.12}/extensions/fourier_transform_functions.rst | 0 spec/{ => 2022.12}/extensions/index.rst | 0 spec/{ => 2022.12}/extensions/linear_algebra_functions.rst | 0 spec/{ => 2022.12}/future_API_evolution.md | 0 spec/{ => 2022.12}/index.rst | 0 spec/{ => 2022.12}/purpose_and_scope.md | 0 spec/{ => 2022.12}/usage_data.md | 0 spec/{ => 2022.12}/use_cases.md | 0 spec/{ => 2022.12}/verification_test_suite.md | 0 .../array_api => src/array_api_stubs/_2022_12}/__init__.py | 0 .../array_api => src/array_api_stubs/_2022_12}/_types.py | 0 .../array_api => src/array_api_stubs/_2022_12}/array_object.py | 0 .../array_api => src/array_api_stubs/_2022_12}/constants.py | 0 .../array_api_stubs/_2022_12}/creation_functions.py | 0 .../array_api_stubs/_2022_12}/data_type_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/data_types.py | 0 .../array_api_stubs/_2022_12}/elementwise_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/fft.py | 0 .../array_api_stubs/_2022_12}/indexing_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/linalg.py | 0 .../array_api_stubs/_2022_12}/linear_algebra_functions.py | 0 .../array_api_stubs/_2022_12}/manipulation_functions.py | 0 .../array_api_stubs/_2022_12}/searching_functions.py | 0 .../array_api => src/array_api_stubs/_2022_12}/set_functions.py | 0 .../array_api_stubs/_2022_12}/sorting_functions.py | 0 .../array_api_stubs/_2022_12}/statistical_functions.py | 0 .../array_api_stubs/_2022_12}/utility_functions.py | 0 60 files changed, 0 insertions(+), 0 deletions(-) rename spec/{ => 2022.12}/API_specification/array_object.rst (100%) rename spec/{ => 2022.12}/API_specification/broadcasting.rst (100%) rename spec/{ => 2022.12}/API_specification/constants.rst (100%) rename spec/{ => 2022.12}/API_specification/creation_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/data_type_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/data_types.rst (100%) rename spec/{ => 2022.12}/API_specification/elementwise_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/function_and_method_signatures.rst (100%) rename spec/{ => 2022.12}/API_specification/index.rst (100%) rename spec/{ => 2022.12}/API_specification/indexing.rst (100%) rename spec/{ => 2022.12}/API_specification/indexing_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/linear_algebra_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/manipulation_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/searching_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/set_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/sorting_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/statistical_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/type_promotion.rst (100%) rename spec/{ => 2022.12}/API_specification/utility_functions.rst (100%) rename spec/{ => 2022.12}/API_specification/version.rst (100%) rename spec/{ => 2022.12}/assumptions.md (100%) rename spec/{ => 2022.12}/benchmark_suite.md (100%) rename spec/{ => 2022.12}/changelog.rst (100%) rename spec/{ => 2022.12}/design_topics/C_API.rst (100%) rename spec/{ => 2022.12}/design_topics/accuracy.rst (100%) rename spec/{ => 2022.12}/design_topics/complex_numbers.rst (100%) rename spec/{ => 2022.12}/design_topics/copies_views_and_mutation.rst (100%) rename spec/{ => 2022.12}/design_topics/data_dependent_output_shapes.rst (100%) rename spec/{ => 2022.12}/design_topics/data_interchange.rst (100%) rename spec/{ => 2022.12}/design_topics/device_support.rst (100%) rename spec/{ => 2022.12}/design_topics/index.rst (100%) rename spec/{ => 2022.12}/design_topics/parallelism.rst (100%) rename spec/{ => 2022.12}/design_topics/static_typing.rst (100%) rename spec/{ => 2022.12}/extensions/fourier_transform_functions.rst (100%) rename spec/{ => 2022.12}/extensions/index.rst (100%) rename spec/{ => 2022.12}/extensions/linear_algebra_functions.rst (100%) rename spec/{ => 2022.12}/future_API_evolution.md (100%) rename spec/{ => 2022.12}/index.rst (100%) rename spec/{ => 2022.12}/purpose_and_scope.md (100%) rename spec/{ => 2022.12}/usage_data.md (100%) rename spec/{ => 2022.12}/use_cases.md (100%) rename spec/{ => 2022.12}/verification_test_suite.md (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/__init__.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/_types.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/array_object.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/constants.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/creation_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/data_type_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/data_types.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/elementwise_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/fft.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/indexing_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/linalg.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/linear_algebra_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/manipulation_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/searching_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/set_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/sorting_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/statistical_functions.py (100%) rename {spec/API_specification/array_api => src/array_api_stubs/_2022_12}/utility_functions.py (100%) diff --git a/spec/API_specification/array_object.rst b/spec/2022.12/API_specification/array_object.rst similarity index 100% rename from spec/API_specification/array_object.rst rename to spec/2022.12/API_specification/array_object.rst diff --git a/spec/API_specification/broadcasting.rst b/spec/2022.12/API_specification/broadcasting.rst similarity index 100% rename from spec/API_specification/broadcasting.rst rename to spec/2022.12/API_specification/broadcasting.rst diff --git a/spec/API_specification/constants.rst b/spec/2022.12/API_specification/constants.rst similarity index 100% rename from spec/API_specification/constants.rst rename to spec/2022.12/API_specification/constants.rst diff --git a/spec/API_specification/creation_functions.rst b/spec/2022.12/API_specification/creation_functions.rst similarity index 100% rename from spec/API_specification/creation_functions.rst rename to spec/2022.12/API_specification/creation_functions.rst diff --git a/spec/API_specification/data_type_functions.rst b/spec/2022.12/API_specification/data_type_functions.rst similarity index 100% rename from spec/API_specification/data_type_functions.rst rename to spec/2022.12/API_specification/data_type_functions.rst diff --git a/spec/API_specification/data_types.rst b/spec/2022.12/API_specification/data_types.rst similarity index 100% rename from spec/API_specification/data_types.rst rename to spec/2022.12/API_specification/data_types.rst diff --git a/spec/API_specification/elementwise_functions.rst b/spec/2022.12/API_specification/elementwise_functions.rst similarity index 100% rename from spec/API_specification/elementwise_functions.rst rename to spec/2022.12/API_specification/elementwise_functions.rst diff --git a/spec/API_specification/function_and_method_signatures.rst b/spec/2022.12/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/API_specification/function_and_method_signatures.rst rename to spec/2022.12/API_specification/function_and_method_signatures.rst diff --git a/spec/API_specification/index.rst b/spec/2022.12/API_specification/index.rst similarity index 100% rename from spec/API_specification/index.rst rename to spec/2022.12/API_specification/index.rst diff --git a/spec/API_specification/indexing.rst b/spec/2022.12/API_specification/indexing.rst similarity index 100% rename from spec/API_specification/indexing.rst rename to spec/2022.12/API_specification/indexing.rst diff --git a/spec/API_specification/indexing_functions.rst b/spec/2022.12/API_specification/indexing_functions.rst similarity index 100% rename from spec/API_specification/indexing_functions.rst rename to spec/2022.12/API_specification/indexing_functions.rst diff --git a/spec/API_specification/linear_algebra_functions.rst b/spec/2022.12/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/API_specification/linear_algebra_functions.rst rename to spec/2022.12/API_specification/linear_algebra_functions.rst diff --git a/spec/API_specification/manipulation_functions.rst b/spec/2022.12/API_specification/manipulation_functions.rst similarity index 100% rename from spec/API_specification/manipulation_functions.rst rename to spec/2022.12/API_specification/manipulation_functions.rst diff --git a/spec/API_specification/searching_functions.rst b/spec/2022.12/API_specification/searching_functions.rst similarity index 100% rename from spec/API_specification/searching_functions.rst rename to spec/2022.12/API_specification/searching_functions.rst diff --git a/spec/API_specification/set_functions.rst b/spec/2022.12/API_specification/set_functions.rst similarity index 100% rename from spec/API_specification/set_functions.rst rename to spec/2022.12/API_specification/set_functions.rst diff --git a/spec/API_specification/sorting_functions.rst b/spec/2022.12/API_specification/sorting_functions.rst similarity index 100% rename from spec/API_specification/sorting_functions.rst rename to spec/2022.12/API_specification/sorting_functions.rst diff --git a/spec/API_specification/statistical_functions.rst b/spec/2022.12/API_specification/statistical_functions.rst similarity index 100% rename from spec/API_specification/statistical_functions.rst rename to spec/2022.12/API_specification/statistical_functions.rst diff --git a/spec/API_specification/type_promotion.rst b/spec/2022.12/API_specification/type_promotion.rst similarity index 100% rename from spec/API_specification/type_promotion.rst rename to spec/2022.12/API_specification/type_promotion.rst diff --git a/spec/API_specification/utility_functions.rst b/spec/2022.12/API_specification/utility_functions.rst similarity index 100% rename from spec/API_specification/utility_functions.rst rename to spec/2022.12/API_specification/utility_functions.rst diff --git a/spec/API_specification/version.rst b/spec/2022.12/API_specification/version.rst similarity index 100% rename from spec/API_specification/version.rst rename to spec/2022.12/API_specification/version.rst diff --git a/spec/assumptions.md b/spec/2022.12/assumptions.md similarity index 100% rename from spec/assumptions.md rename to spec/2022.12/assumptions.md diff --git a/spec/benchmark_suite.md b/spec/2022.12/benchmark_suite.md similarity index 100% rename from spec/benchmark_suite.md rename to spec/2022.12/benchmark_suite.md diff --git a/spec/changelog.rst b/spec/2022.12/changelog.rst similarity index 100% rename from spec/changelog.rst rename to spec/2022.12/changelog.rst diff --git a/spec/design_topics/C_API.rst b/spec/2022.12/design_topics/C_API.rst similarity index 100% rename from spec/design_topics/C_API.rst rename to spec/2022.12/design_topics/C_API.rst diff --git a/spec/design_topics/accuracy.rst b/spec/2022.12/design_topics/accuracy.rst similarity index 100% rename from spec/design_topics/accuracy.rst rename to spec/2022.12/design_topics/accuracy.rst diff --git a/spec/design_topics/complex_numbers.rst b/spec/2022.12/design_topics/complex_numbers.rst similarity index 100% rename from spec/design_topics/complex_numbers.rst rename to spec/2022.12/design_topics/complex_numbers.rst diff --git a/spec/design_topics/copies_views_and_mutation.rst b/spec/2022.12/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/design_topics/copies_views_and_mutation.rst rename to spec/2022.12/design_topics/copies_views_and_mutation.rst diff --git a/spec/design_topics/data_dependent_output_shapes.rst b/spec/2022.12/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/design_topics/data_dependent_output_shapes.rst rename to spec/2022.12/design_topics/data_dependent_output_shapes.rst diff --git a/spec/design_topics/data_interchange.rst b/spec/2022.12/design_topics/data_interchange.rst similarity index 100% rename from spec/design_topics/data_interchange.rst rename to spec/2022.12/design_topics/data_interchange.rst diff --git a/spec/design_topics/device_support.rst b/spec/2022.12/design_topics/device_support.rst similarity index 100% rename from spec/design_topics/device_support.rst rename to spec/2022.12/design_topics/device_support.rst diff --git a/spec/design_topics/index.rst b/spec/2022.12/design_topics/index.rst similarity index 100% rename from spec/design_topics/index.rst rename to spec/2022.12/design_topics/index.rst diff --git a/spec/design_topics/parallelism.rst b/spec/2022.12/design_topics/parallelism.rst similarity index 100% rename from spec/design_topics/parallelism.rst rename to spec/2022.12/design_topics/parallelism.rst diff --git a/spec/design_topics/static_typing.rst b/spec/2022.12/design_topics/static_typing.rst similarity index 100% rename from spec/design_topics/static_typing.rst rename to spec/2022.12/design_topics/static_typing.rst diff --git a/spec/extensions/fourier_transform_functions.rst b/spec/2022.12/extensions/fourier_transform_functions.rst similarity index 100% rename from spec/extensions/fourier_transform_functions.rst rename to spec/2022.12/extensions/fourier_transform_functions.rst diff --git a/spec/extensions/index.rst b/spec/2022.12/extensions/index.rst similarity index 100% rename from spec/extensions/index.rst rename to spec/2022.12/extensions/index.rst diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/2022.12/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/extensions/linear_algebra_functions.rst rename to spec/2022.12/extensions/linear_algebra_functions.rst diff --git a/spec/future_API_evolution.md b/spec/2022.12/future_API_evolution.md similarity index 100% rename from spec/future_API_evolution.md rename to spec/2022.12/future_API_evolution.md diff --git a/spec/index.rst b/spec/2022.12/index.rst similarity index 100% rename from spec/index.rst rename to spec/2022.12/index.rst diff --git a/spec/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md similarity index 100% rename from spec/purpose_and_scope.md rename to spec/2022.12/purpose_and_scope.md diff --git a/spec/usage_data.md b/spec/2022.12/usage_data.md similarity index 100% rename from spec/usage_data.md rename to spec/2022.12/usage_data.md diff --git a/spec/use_cases.md b/spec/2022.12/use_cases.md similarity index 100% rename from spec/use_cases.md rename to spec/2022.12/use_cases.md diff --git a/spec/verification_test_suite.md b/spec/2022.12/verification_test_suite.md similarity index 100% rename from spec/verification_test_suite.md rename to spec/2022.12/verification_test_suite.md diff --git a/spec/API_specification/array_api/__init__.py b/src/array_api_stubs/_2022_12/__init__.py similarity index 100% rename from spec/API_specification/array_api/__init__.py rename to src/array_api_stubs/_2022_12/__init__.py diff --git a/spec/API_specification/array_api/_types.py b/src/array_api_stubs/_2022_12/_types.py similarity index 100% rename from spec/API_specification/array_api/_types.py rename to src/array_api_stubs/_2022_12/_types.py diff --git a/spec/API_specification/array_api/array_object.py b/src/array_api_stubs/_2022_12/array_object.py similarity index 100% rename from spec/API_specification/array_api/array_object.py rename to src/array_api_stubs/_2022_12/array_object.py diff --git a/spec/API_specification/array_api/constants.py b/src/array_api_stubs/_2022_12/constants.py similarity index 100% rename from spec/API_specification/array_api/constants.py rename to src/array_api_stubs/_2022_12/constants.py diff --git a/spec/API_specification/array_api/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py similarity index 100% rename from spec/API_specification/array_api/creation_functions.py rename to src/array_api_stubs/_2022_12/creation_functions.py diff --git a/spec/API_specification/array_api/data_type_functions.py b/src/array_api_stubs/_2022_12/data_type_functions.py similarity index 100% rename from spec/API_specification/array_api/data_type_functions.py rename to src/array_api_stubs/_2022_12/data_type_functions.py diff --git a/spec/API_specification/array_api/data_types.py b/src/array_api_stubs/_2022_12/data_types.py similarity index 100% rename from spec/API_specification/array_api/data_types.py rename to src/array_api_stubs/_2022_12/data_types.py diff --git a/spec/API_specification/array_api/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py similarity index 100% rename from spec/API_specification/array_api/elementwise_functions.py rename to src/array_api_stubs/_2022_12/elementwise_functions.py diff --git a/spec/API_specification/array_api/fft.py b/src/array_api_stubs/_2022_12/fft.py similarity index 100% rename from spec/API_specification/array_api/fft.py rename to src/array_api_stubs/_2022_12/fft.py diff --git a/spec/API_specification/array_api/indexing_functions.py b/src/array_api_stubs/_2022_12/indexing_functions.py similarity index 100% rename from spec/API_specification/array_api/indexing_functions.py rename to src/array_api_stubs/_2022_12/indexing_functions.py diff --git a/spec/API_specification/array_api/linalg.py b/src/array_api_stubs/_2022_12/linalg.py similarity index 100% rename from spec/API_specification/array_api/linalg.py rename to src/array_api_stubs/_2022_12/linalg.py diff --git a/spec/API_specification/array_api/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py similarity index 100% rename from spec/API_specification/array_api/linear_algebra_functions.py rename to src/array_api_stubs/_2022_12/linear_algebra_functions.py diff --git a/spec/API_specification/array_api/manipulation_functions.py b/src/array_api_stubs/_2022_12/manipulation_functions.py similarity index 100% rename from spec/API_specification/array_api/manipulation_functions.py rename to src/array_api_stubs/_2022_12/manipulation_functions.py diff --git a/spec/API_specification/array_api/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py similarity index 100% rename from spec/API_specification/array_api/searching_functions.py rename to src/array_api_stubs/_2022_12/searching_functions.py diff --git a/spec/API_specification/array_api/set_functions.py b/src/array_api_stubs/_2022_12/set_functions.py similarity index 100% rename from spec/API_specification/array_api/set_functions.py rename to src/array_api_stubs/_2022_12/set_functions.py diff --git a/spec/API_specification/array_api/sorting_functions.py b/src/array_api_stubs/_2022_12/sorting_functions.py similarity index 100% rename from spec/API_specification/array_api/sorting_functions.py rename to src/array_api_stubs/_2022_12/sorting_functions.py diff --git a/spec/API_specification/array_api/statistical_functions.py b/src/array_api_stubs/_2022_12/statistical_functions.py similarity index 100% rename from spec/API_specification/array_api/statistical_functions.py rename to src/array_api_stubs/_2022_12/statistical_functions.py diff --git a/spec/API_specification/array_api/utility_functions.py b/src/array_api_stubs/_2022_12/utility_functions.py similarity index 100% rename from spec/API_specification/array_api/utility_functions.py rename to src/array_api_stubs/_2022_12/utility_functions.py From 314d1a9297ba602e0eefa8a805b69310c7f1409b Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 3 Jan 2023 17:08:29 +0000 Subject: [PATCH 357/551] Move old `2021.12` docs to respective sub-folders --- spec/{ => 2021.12}/API_specification/array_object.rst | 0 spec/{ => 2021.12}/API_specification/broadcasting.rst | 0 spec/{ => 2021.12}/API_specification/constants.rst | 0 spec/{ => 2021.12}/API_specification/creation_functions.rst | 0 spec/{ => 2021.12}/API_specification/data_type_functions.rst | 0 spec/{ => 2021.12}/API_specification/data_types.rst | 0 spec/{ => 2021.12}/API_specification/elementwise_functions.rst | 0 .../API_specification/function_and_method_signatures.rst | 0 spec/{ => 2021.12}/API_specification/index.rst | 0 spec/{ => 2021.12}/API_specification/indexing.rst | 0 spec/{ => 2021.12}/API_specification/linear_algebra_functions.rst | 0 spec/{ => 2021.12}/API_specification/manipulation_functions.rst | 0 spec/{ => 2021.12}/API_specification/searching_functions.rst | 0 spec/{ => 2021.12}/API_specification/set_functions.rst | 0 spec/{ => 2021.12}/API_specification/sorting_functions.rst | 0 spec/{ => 2021.12}/API_specification/statistical_functions.rst | 0 spec/{ => 2021.12}/API_specification/type_promotion.rst | 0 spec/{ => 2021.12}/API_specification/utility_functions.rst | 0 spec/{ => 2021.12}/assumptions.md | 0 spec/{ => 2021.12}/benchmark_suite.md | 0 spec/{ => 2021.12}/conf.py | 0 spec/{ => 2021.12}/design_topics/C_API.rst | 0 spec/{ => 2021.12}/design_topics/accuracy.rst | 0 spec/{ => 2021.12}/design_topics/copies_views_and_mutation.rst | 0 spec/{ => 2021.12}/design_topics/data_dependent_output_shapes.rst | 0 spec/{ => 2021.12}/design_topics/data_interchange.rst | 0 spec/{ => 2021.12}/design_topics/device_support.rst | 0 spec/{ => 2021.12}/design_topics/index.rst | 0 spec/{ => 2021.12}/design_topics/parallelism.rst | 0 spec/{ => 2021.12}/design_topics/static_typing.rst | 0 spec/{ => 2021.12}/extensions/index.rst | 0 spec/{ => 2021.12}/extensions/linear_algebra_functions.rst | 0 spec/{ => 2021.12}/future_API_evolution.md | 0 spec/{ => 2021.12}/index.rst | 0 spec/{ => 2021.12}/purpose_and_scope.md | 0 spec/{ => 2021.12}/usage_data.md | 0 spec/{ => 2021.12}/use_cases.md | 0 spec/{ => 2021.12}/verification_test_suite.md | 0 .../signatures => src/array_api_stubs/_2021_12}/__init__.py | 0 .../signatures => src/array_api_stubs/_2021_12}/_types.py | 0 .../signatures => src/array_api_stubs/_2021_12}/array_object.py | 0 .../signatures => src/array_api_stubs/_2021_12}/constants.py | 0 .../array_api_stubs/_2021_12}/creation_functions.py | 0 .../array_api_stubs/_2021_12}/data_type_functions.py | 0 .../signatures => src/array_api_stubs/_2021_12}/data_types.py | 0 .../array_api_stubs/_2021_12}/elementwise_functions.py | 0 .../signatures => src/array_api_stubs/_2021_12}/linalg.py | 0 .../array_api_stubs/_2021_12}/linear_algebra_functions.py | 0 .../array_api_stubs/_2021_12}/manipulation_functions.py | 0 .../array_api_stubs/_2021_12}/searching_functions.py | 0 .../signatures => src/array_api_stubs/_2021_12}/set_functions.py | 0 .../array_api_stubs/_2021_12}/sorting_functions.py | 0 .../array_api_stubs/_2021_12}/statistical_functions.py | 0 .../array_api_stubs/_2021_12}/utility_functions.py | 0 54 files changed, 0 insertions(+), 0 deletions(-) rename spec/{ => 2021.12}/API_specification/array_object.rst (100%) rename spec/{ => 2021.12}/API_specification/broadcasting.rst (100%) rename spec/{ => 2021.12}/API_specification/constants.rst (100%) rename spec/{ => 2021.12}/API_specification/creation_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/data_type_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/data_types.rst (100%) rename spec/{ => 2021.12}/API_specification/elementwise_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/function_and_method_signatures.rst (100%) rename spec/{ => 2021.12}/API_specification/index.rst (100%) rename spec/{ => 2021.12}/API_specification/indexing.rst (100%) rename spec/{ => 2021.12}/API_specification/linear_algebra_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/manipulation_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/searching_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/set_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/sorting_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/statistical_functions.rst (100%) rename spec/{ => 2021.12}/API_specification/type_promotion.rst (100%) rename spec/{ => 2021.12}/API_specification/utility_functions.rst (100%) rename spec/{ => 2021.12}/assumptions.md (100%) rename spec/{ => 2021.12}/benchmark_suite.md (100%) rename spec/{ => 2021.12}/conf.py (100%) rename spec/{ => 2021.12}/design_topics/C_API.rst (100%) rename spec/{ => 2021.12}/design_topics/accuracy.rst (100%) rename spec/{ => 2021.12}/design_topics/copies_views_and_mutation.rst (100%) rename spec/{ => 2021.12}/design_topics/data_dependent_output_shapes.rst (100%) rename spec/{ => 2021.12}/design_topics/data_interchange.rst (100%) rename spec/{ => 2021.12}/design_topics/device_support.rst (100%) rename spec/{ => 2021.12}/design_topics/index.rst (100%) rename spec/{ => 2021.12}/design_topics/parallelism.rst (100%) rename spec/{ => 2021.12}/design_topics/static_typing.rst (100%) rename spec/{ => 2021.12}/extensions/index.rst (100%) rename spec/{ => 2021.12}/extensions/linear_algebra_functions.rst (100%) rename spec/{ => 2021.12}/future_API_evolution.md (100%) rename spec/{ => 2021.12}/index.rst (100%) rename spec/{ => 2021.12}/purpose_and_scope.md (100%) rename spec/{ => 2021.12}/usage_data.md (100%) rename spec/{ => 2021.12}/use_cases.md (100%) rename spec/{ => 2021.12}/verification_test_suite.md (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/__init__.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/_types.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/array_object.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/constants.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/creation_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/data_type_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/data_types.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/elementwise_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/linalg.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/linear_algebra_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/manipulation_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/searching_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/set_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/sorting_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/statistical_functions.py (100%) rename {spec/API_specification/signatures => src/array_api_stubs/_2021_12}/utility_functions.py (100%) diff --git a/spec/API_specification/array_object.rst b/spec/2021.12/API_specification/array_object.rst similarity index 100% rename from spec/API_specification/array_object.rst rename to spec/2021.12/API_specification/array_object.rst diff --git a/spec/API_specification/broadcasting.rst b/spec/2021.12/API_specification/broadcasting.rst similarity index 100% rename from spec/API_specification/broadcasting.rst rename to spec/2021.12/API_specification/broadcasting.rst diff --git a/spec/API_specification/constants.rst b/spec/2021.12/API_specification/constants.rst similarity index 100% rename from spec/API_specification/constants.rst rename to spec/2021.12/API_specification/constants.rst diff --git a/spec/API_specification/creation_functions.rst b/spec/2021.12/API_specification/creation_functions.rst similarity index 100% rename from spec/API_specification/creation_functions.rst rename to spec/2021.12/API_specification/creation_functions.rst diff --git a/spec/API_specification/data_type_functions.rst b/spec/2021.12/API_specification/data_type_functions.rst similarity index 100% rename from spec/API_specification/data_type_functions.rst rename to spec/2021.12/API_specification/data_type_functions.rst diff --git a/spec/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst similarity index 100% rename from spec/API_specification/data_types.rst rename to spec/2021.12/API_specification/data_types.rst diff --git a/spec/API_specification/elementwise_functions.rst b/spec/2021.12/API_specification/elementwise_functions.rst similarity index 100% rename from spec/API_specification/elementwise_functions.rst rename to spec/2021.12/API_specification/elementwise_functions.rst diff --git a/spec/API_specification/function_and_method_signatures.rst b/spec/2021.12/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/API_specification/function_and_method_signatures.rst rename to spec/2021.12/API_specification/function_and_method_signatures.rst diff --git a/spec/API_specification/index.rst b/spec/2021.12/API_specification/index.rst similarity index 100% rename from spec/API_specification/index.rst rename to spec/2021.12/API_specification/index.rst diff --git a/spec/API_specification/indexing.rst b/spec/2021.12/API_specification/indexing.rst similarity index 100% rename from spec/API_specification/indexing.rst rename to spec/2021.12/API_specification/indexing.rst diff --git a/spec/API_specification/linear_algebra_functions.rst b/spec/2021.12/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/API_specification/linear_algebra_functions.rst rename to spec/2021.12/API_specification/linear_algebra_functions.rst diff --git a/spec/API_specification/manipulation_functions.rst b/spec/2021.12/API_specification/manipulation_functions.rst similarity index 100% rename from spec/API_specification/manipulation_functions.rst rename to spec/2021.12/API_specification/manipulation_functions.rst diff --git a/spec/API_specification/searching_functions.rst b/spec/2021.12/API_specification/searching_functions.rst similarity index 100% rename from spec/API_specification/searching_functions.rst rename to spec/2021.12/API_specification/searching_functions.rst diff --git a/spec/API_specification/set_functions.rst b/spec/2021.12/API_specification/set_functions.rst similarity index 100% rename from spec/API_specification/set_functions.rst rename to spec/2021.12/API_specification/set_functions.rst diff --git a/spec/API_specification/sorting_functions.rst b/spec/2021.12/API_specification/sorting_functions.rst similarity index 100% rename from spec/API_specification/sorting_functions.rst rename to spec/2021.12/API_specification/sorting_functions.rst diff --git a/spec/API_specification/statistical_functions.rst b/spec/2021.12/API_specification/statistical_functions.rst similarity index 100% rename from spec/API_specification/statistical_functions.rst rename to spec/2021.12/API_specification/statistical_functions.rst diff --git a/spec/API_specification/type_promotion.rst b/spec/2021.12/API_specification/type_promotion.rst similarity index 100% rename from spec/API_specification/type_promotion.rst rename to spec/2021.12/API_specification/type_promotion.rst diff --git a/spec/API_specification/utility_functions.rst b/spec/2021.12/API_specification/utility_functions.rst similarity index 100% rename from spec/API_specification/utility_functions.rst rename to spec/2021.12/API_specification/utility_functions.rst diff --git a/spec/assumptions.md b/spec/2021.12/assumptions.md similarity index 100% rename from spec/assumptions.md rename to spec/2021.12/assumptions.md diff --git a/spec/benchmark_suite.md b/spec/2021.12/benchmark_suite.md similarity index 100% rename from spec/benchmark_suite.md rename to spec/2021.12/benchmark_suite.md diff --git a/spec/conf.py b/spec/2021.12/conf.py similarity index 100% rename from spec/conf.py rename to spec/2021.12/conf.py diff --git a/spec/design_topics/C_API.rst b/spec/2021.12/design_topics/C_API.rst similarity index 100% rename from spec/design_topics/C_API.rst rename to spec/2021.12/design_topics/C_API.rst diff --git a/spec/design_topics/accuracy.rst b/spec/2021.12/design_topics/accuracy.rst similarity index 100% rename from spec/design_topics/accuracy.rst rename to spec/2021.12/design_topics/accuracy.rst diff --git a/spec/design_topics/copies_views_and_mutation.rst b/spec/2021.12/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/design_topics/copies_views_and_mutation.rst rename to spec/2021.12/design_topics/copies_views_and_mutation.rst diff --git a/spec/design_topics/data_dependent_output_shapes.rst b/spec/2021.12/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/design_topics/data_dependent_output_shapes.rst rename to spec/2021.12/design_topics/data_dependent_output_shapes.rst diff --git a/spec/design_topics/data_interchange.rst b/spec/2021.12/design_topics/data_interchange.rst similarity index 100% rename from spec/design_topics/data_interchange.rst rename to spec/2021.12/design_topics/data_interchange.rst diff --git a/spec/design_topics/device_support.rst b/spec/2021.12/design_topics/device_support.rst similarity index 100% rename from spec/design_topics/device_support.rst rename to spec/2021.12/design_topics/device_support.rst diff --git a/spec/design_topics/index.rst b/spec/2021.12/design_topics/index.rst similarity index 100% rename from spec/design_topics/index.rst rename to spec/2021.12/design_topics/index.rst diff --git a/spec/design_topics/parallelism.rst b/spec/2021.12/design_topics/parallelism.rst similarity index 100% rename from spec/design_topics/parallelism.rst rename to spec/2021.12/design_topics/parallelism.rst diff --git a/spec/design_topics/static_typing.rst b/spec/2021.12/design_topics/static_typing.rst similarity index 100% rename from spec/design_topics/static_typing.rst rename to spec/2021.12/design_topics/static_typing.rst diff --git a/spec/extensions/index.rst b/spec/2021.12/extensions/index.rst similarity index 100% rename from spec/extensions/index.rst rename to spec/2021.12/extensions/index.rst diff --git a/spec/extensions/linear_algebra_functions.rst b/spec/2021.12/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/extensions/linear_algebra_functions.rst rename to spec/2021.12/extensions/linear_algebra_functions.rst diff --git a/spec/future_API_evolution.md b/spec/2021.12/future_API_evolution.md similarity index 100% rename from spec/future_API_evolution.md rename to spec/2021.12/future_API_evolution.md diff --git a/spec/index.rst b/spec/2021.12/index.rst similarity index 100% rename from spec/index.rst rename to spec/2021.12/index.rst diff --git a/spec/purpose_and_scope.md b/spec/2021.12/purpose_and_scope.md similarity index 100% rename from spec/purpose_and_scope.md rename to spec/2021.12/purpose_and_scope.md diff --git a/spec/usage_data.md b/spec/2021.12/usage_data.md similarity index 100% rename from spec/usage_data.md rename to spec/2021.12/usage_data.md diff --git a/spec/use_cases.md b/spec/2021.12/use_cases.md similarity index 100% rename from spec/use_cases.md rename to spec/2021.12/use_cases.md diff --git a/spec/verification_test_suite.md b/spec/2021.12/verification_test_suite.md similarity index 100% rename from spec/verification_test_suite.md rename to spec/2021.12/verification_test_suite.md diff --git a/spec/API_specification/signatures/__init__.py b/src/array_api_stubs/_2021_12/__init__.py similarity index 100% rename from spec/API_specification/signatures/__init__.py rename to src/array_api_stubs/_2021_12/__init__.py diff --git a/spec/API_specification/signatures/_types.py b/src/array_api_stubs/_2021_12/_types.py similarity index 100% rename from spec/API_specification/signatures/_types.py rename to src/array_api_stubs/_2021_12/_types.py diff --git a/spec/API_specification/signatures/array_object.py b/src/array_api_stubs/_2021_12/array_object.py similarity index 100% rename from spec/API_specification/signatures/array_object.py rename to src/array_api_stubs/_2021_12/array_object.py diff --git a/spec/API_specification/signatures/constants.py b/src/array_api_stubs/_2021_12/constants.py similarity index 100% rename from spec/API_specification/signatures/constants.py rename to src/array_api_stubs/_2021_12/constants.py diff --git a/spec/API_specification/signatures/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py similarity index 100% rename from spec/API_specification/signatures/creation_functions.py rename to src/array_api_stubs/_2021_12/creation_functions.py diff --git a/spec/API_specification/signatures/data_type_functions.py b/src/array_api_stubs/_2021_12/data_type_functions.py similarity index 100% rename from spec/API_specification/signatures/data_type_functions.py rename to src/array_api_stubs/_2021_12/data_type_functions.py diff --git a/spec/API_specification/signatures/data_types.py b/src/array_api_stubs/_2021_12/data_types.py similarity index 100% rename from spec/API_specification/signatures/data_types.py rename to src/array_api_stubs/_2021_12/data_types.py diff --git a/spec/API_specification/signatures/elementwise_functions.py b/src/array_api_stubs/_2021_12/elementwise_functions.py similarity index 100% rename from spec/API_specification/signatures/elementwise_functions.py rename to src/array_api_stubs/_2021_12/elementwise_functions.py diff --git a/spec/API_specification/signatures/linalg.py b/src/array_api_stubs/_2021_12/linalg.py similarity index 100% rename from spec/API_specification/signatures/linalg.py rename to src/array_api_stubs/_2021_12/linalg.py diff --git a/spec/API_specification/signatures/linear_algebra_functions.py b/src/array_api_stubs/_2021_12/linear_algebra_functions.py similarity index 100% rename from spec/API_specification/signatures/linear_algebra_functions.py rename to src/array_api_stubs/_2021_12/linear_algebra_functions.py diff --git a/spec/API_specification/signatures/manipulation_functions.py b/src/array_api_stubs/_2021_12/manipulation_functions.py similarity index 100% rename from spec/API_specification/signatures/manipulation_functions.py rename to src/array_api_stubs/_2021_12/manipulation_functions.py diff --git a/spec/API_specification/signatures/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py similarity index 100% rename from spec/API_specification/signatures/searching_functions.py rename to src/array_api_stubs/_2021_12/searching_functions.py diff --git a/spec/API_specification/signatures/set_functions.py b/src/array_api_stubs/_2021_12/set_functions.py similarity index 100% rename from spec/API_specification/signatures/set_functions.py rename to src/array_api_stubs/_2021_12/set_functions.py diff --git a/spec/API_specification/signatures/sorting_functions.py b/src/array_api_stubs/_2021_12/sorting_functions.py similarity index 100% rename from spec/API_specification/signatures/sorting_functions.py rename to src/array_api_stubs/_2021_12/sorting_functions.py diff --git a/spec/API_specification/signatures/statistical_functions.py b/src/array_api_stubs/_2021_12/statistical_functions.py similarity index 100% rename from spec/API_specification/signatures/statistical_functions.py rename to src/array_api_stubs/_2021_12/statistical_functions.py diff --git a/spec/API_specification/signatures/utility_functions.py b/src/array_api_stubs/_2021_12/utility_functions.py similarity index 100% rename from spec/API_specification/signatures/utility_functions.py rename to src/array_api_stubs/_2021_12/utility_functions.py From f56de3c1777256e5727a6f73d2776af17686d754 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:20:15 +0000 Subject: [PATCH 358/551] Squashed previous all-versions work * Rudimentary `array_api_stubs` pkg and folder-per-version docs * Regex nitpick ignore for array types * Move `2021.12` docs to respective sub-folders * Fix autosummary by patching stub sub-modules in `conf.py` * Rudimentary build-all Makefile rule * Specify versions in `conf.py` * Use `versions.json` method for sphinx-material Otherwise don't think we can get links working on nested pages Notably this usually won't work locally - see https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors/CORSRequestNotHttp * Update image paths to shared `_static/` * Use vars in `make build` definition * Expand regex used to identify unwanted type hint prefixes * Update `pages.yml` workflow * Store gh-pages `.gitignore` in `main` to be copied over * `_spec_conf.py` -> `_array_api_conf.py` * Basic package necessities * Replace `requirements.txt` with extra dependency `doc` * Basic local build guide * Update preview workflow * Remove out-of-date make things, new top-level Makefile * Minor `CONTRIBUTING.md` improvements * Basic `_array_api_conf.py` module docstring * Move quickstart to `README.md` * Use `array_api` as opposed to `signatures` for `2021.12` autodoc * More consistent Makefile * Introduce `_ghpages` to hold the non-Sphinx static files * Rudimentary spec release guide * Guide to preserve history for future spec releases --- .circleci/config.yml | 6 +- .github/workflows/pages.yml | 20 +-- .github/workflows/preview.yml | 2 +- .gitignore | 7 +- MANIFEST.in | 3 + Makefile | 22 ++++ PACKAGE.md | 9 ++ README.md | 116 ++++++++++++++++++ pyproject.toml | 30 +++++ requirements.txt | 7 -- spec/Makefile | 25 ---- spec/_ghpages/_gitignore.txt | 36 ++++++ spec/_ghpages/index.html | 10 ++ spec/_ghpages/versions.json | 5 + spec/draft/conf.py | 7 ++ spec/make.bat | 35 ------ src/_array_api_conf.py | 211 ++++++++++++++++++++++++++++++++ src/array_api_stubs/__init__.py | 2 + 18 files changed, 466 insertions(+), 87 deletions(-) create mode 100644 MANIFEST.in create mode 100644 Makefile create mode 100644 PACKAGE.md create mode 100644 pyproject.toml delete mode 100644 requirements.txt delete mode 100644 spec/Makefile create mode 100644 spec/_ghpages/_gitignore.txt create mode 100644 spec/_ghpages/index.html create mode 100644 spec/_ghpages/versions.json create mode 100644 spec/draft/conf.py delete mode 100644 spec/make.bat create mode 100644 src/_array_api_conf.py create mode 100644 src/array_api_stubs/__init__.py diff --git a/.circleci/config.yml b/.circleci/config.yml index aab5a1744..cecae43c8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,10 +19,10 @@ jobs: name: build docs no_output_timeout: 25m command: | - pip install -r requirements.txt - sphinx-build -b html -WT --keep-going spec build/draft -d doctrees + pip install .[doc] + make - store_artifacts: - path: build/draft + path: _site/ workflows: version: 2 diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index fc8a97015..e615135d3 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -76,22 +76,14 @@ jobs: # Install dependencies: - name: 'Install dependencies' run: | - pip install -r ./requirements.txt + pip install .[doc] # Generate the documentation: - name: 'Build documentation' run: | # Turn warnings into errors and ensure .doctrees is not deployed: - sphinx-build -b html -WT --keep-going spec build/draft -d doctrees - - # Upload the build artifact: - - name: 'Upload build artifact' - uses: actions/upload-artifact@v2 - if: ${{ github.event_name == 'pull_request'}} - with: - name: html - path: build/ - if-no-files-found: error + export SPHINXOPTS="-b html -WT --keep-going -d doctrees" + make # Configure Git: - name: 'Configure Git' @@ -107,10 +99,10 @@ jobs: git checkout gh-pages timeout-minutes: 5 - # Copy build artifact: - - name: 'Copy build artifact' + - name: 'Copy build to root' run: | - rm -rf ./draft && cp -R ./build/draft ./draft + cp -R ./_site/* . + cp ./_site/.gitignore . timeout-minutes: 10 # Commit changes to: diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index cdfa3c57b..347dbfb8d 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -11,6 +11,6 @@ jobs: uses: larsoner/circleci-artifacts-redirector-action@master with: repo-token: ${{ secrets.GITHUB_TOKEN }} - artifact-path: 0/build/draft/index.html + artifact-path: 0/_site/draft/index.html circleci-jobs: build_page job-title: Check the rendered docs here! diff --git a/.gitignore b/.gitignore index 86bab2717..d4f538406 100644 --- a/.gitignore +++ b/.gitignore @@ -22,7 +22,7 @@ # SOFTWARE. #/ -spec/_build/ +_site/ doctrees/ build/ .vscode/ @@ -30,4 +30,7 @@ node_modules/ __pycache__/ *.pyc spec/**/generated -tmp/ \ No newline at end of file +tmp/ +*.egg-info/ +*.egg +dist/ diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 000000000..7616b26fd --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,3 @@ +exclude README.md +exclude src/_array_api_conf.py +include PACKAGE.md diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..451b9224c --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +# You can set these variables from the command line. +SPHINXOPTS ?= -W --keep-going +SOURCEDIR = spec +BUILDDIR = _site + +.PHONY: default clean build + +default: clean build + +clean: + -rm -rf $(BUILDDIR) + -find . -type d -name generated -exec rm -rf {} + + +build: + -mkdir -p $(BUILDDIR) + -cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" + -cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" + -cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" + -touch "$(BUILDDIR)/.nojekyll" + -sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) + -cp -r "$(BUILDDIR)/2021.12" "$(BUILDDIR)/latest" + -sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/PACKAGE.md b/PACKAGE.md new file mode 100644 index 000000000..199c4e2a2 --- /dev/null +++ b/PACKAGE.md @@ -0,0 +1,9 @@ +# Stubs for the array API standard + +Documentation specific to singular Python objects in the spec (i.e. functions, +methods and attributes) are infact represented by stub objects in the package +`array-api-stubs`. These stubs ultimately get rendered via the autodoc +capabilities in Sphinx. + +TODO: describe how `array-api-stubs` can be used for tooling, once it actually +has the capacity to do so. diff --git a/README.md b/README.md index d0d88ae4c..96edb338e 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,122 @@ These are relevant documents related to the content in this repository: See [CONTRIBUTING.md](CONTRIBUTING.md) for how to go about contributing to this array API standard. + +## Building docs locally + +The spec website comprises of multiple Sphinx docs (one for each spec version), +all of which exist in `spec/` and rely on the modules found in `src/` (most +notably `array_api_stubs`). To install these modules and the additional +dependencies of the Sphinx docs, you can use + +```sh +$ pip install -e .[doc] # ensure you install the dependencies extra "doc" +``` + +To build specific versions of the spec, run `sphinx-build` on the respective +folder in `spec/`, e.g. + +```sh +$ sphinx-build spec/draft/ _site/draft/ +``` + +To build the whole website, which includes every version of +the spec, you can utilize the `make` commands defined in `spec/Makefile`, e.g. + +```sh +$ make +$ ls _site/ +2021.12/ draft/ index.html latest/ versions.json +``` + + +## Making a spec release + +The Sphinx doc at `spec/draft/` should be where the in-development spec resides, +with `src/array_api_stubs/_draft/` containing its respective stubs. A spec +release should involve: + +* Renaming `src/array_api_stubs/_draft/` to `src/array_api_stubs/_YYYY_MM` +* Renaming `spec/draft/` to `spec/YYYY.MM` +* Updating `spec/YYYY.MM/conf.py` + + ```diff + ... + - from array_api_stubs import _draft as stubs_mod + + from array_api_stubs import _YYYY_MM as stubs_mod + ... + - release = "DRAFT" + + release = "YYYY.MM" + ... + ``` + +* Updating `spec/_ghpages/versions.json` + + ```diff + { + + "YYYY.MM": "YYYY.MM", + ... + ``` + +* Updating `Makefile` + + ```diff + ... + -sphinx-build "$(SOURCEDIR)/PREVIOUS.VER" "$(BUILDDIR)/PREVIOUS.VER" $(SPHINXOPTS) + + -sphinx-build "$(SOURCEDIR)/YYYY.MM" "$(BUILDDIR)/YYYY.MM" $(SPHINXOPTS) + - -cp -r "$(BUILDDIR)/PREVIOUS.VER" "$(BUILDDIR)/latest" + + -cp -r "$(BUILDDIR)/YYYY.MM" "$(BUILDDIR)/latest" + ... + ``` + +These changes should be committed and tagged. The next draft should then be +created. To preserve git history for both the new release and the next draft: + +1. Create and checkout to a new temporary branch. + + ```sh + $ git checkout -b tmp + ``` + +2. Make an empty commit. This is required so merging the temporary branch + (4.) is not automatic. + + ```sh + $ git commit --allow-empty -m "Empty commit for draft at YYYY.MM " + ``` + +3. Checkout back to the branch you are making a spec release in. + + ```sh + $ git checkout YYYY.MM-release + ``` + +4. Merge the temporary branch, specifying no commit and no fast-forwarding. + + ```sh + $ git merge --no-commit --no-ff tmp + Automatic merge went well; stopped before committing as requested + ``` + +5. Checkout the `spec/draft/` files from the temporary branch. + + ```sh + $ git checkout tmp -- spec/draft/ + ``` + +6. Commit your changes. + + ```sh + $ git commit -m "Copy YYYY.MM as draft with preserved git history" + ``` + +You can run `git blame` on both `spec/YYYY.MM` and `spec/draft` files to verify +we've preserved history. See this [StackOverflow question](https://stackoverflow.com/q/74365771/5193926) +for more background on the approach we use. + + + + ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..b8240a665 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,30 @@ +[project] +name = "array-api-stubs" +version = "0.0.2" +description = "Stubs for the array API standard" +authors = [] +license = {file = "LICENSE"} +readme = "PACKAGE.md" +requires-python = ">=3.8" +keywords = [] +classifiers = [] + +[project.urls] +Source = "https://github.com/data-apis/array-api/" +Documentation = "https://data-apis.org/array-api/" +Homepage = "https://data-apis.org/" + +[project.optional-dependencies] +doc = [ + "sphinx==4.3.0", + "sphinx-material==0.0.30", + "myst-parser", + "sphinx_markdown_tables", + "sphinx_copybutton", + "docutils<0.18", + "sphinx-math-dollar", +] + +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 230413784..000000000 --- a/requirements.txt +++ /dev/null @@ -1,7 +0,0 @@ -sphinx==4.3.0 -sphinx-material==0.0.30 -myst-parser -sphinx_markdown_tables -sphinx_copybutton -docutils<0.18 -sphinx-math-dollar diff --git a/spec/Makefile b/spec/Makefile deleted file mode 100644 index e71fa39e1..000000000 --- a/spec/Makefile +++ /dev/null @@ -1,25 +0,0 @@ -# Minimal makefile for Sphinx documentation -# - -# You can set these variables from the command line, and also -# from the environment for the first two. -SPHINXOPTS ?= -W --keep-going -SPHINXBUILD ?= sphinx-build -SOURCEDIR = . -BUILDDIR = _build - -# Put it first so that "make" without argument is like "make help". -help: - @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -.PHONY: help Makefile clean - -# Catch-all target: route all unknown targets to Sphinx using the new -# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) - -clean: - -rm -rf $(BUILDDIR) - -rm -rf "$(SOURCEDIR)/API_specification/generated" - -rm -rf "$(SOURCEDIR)/extensions/generated" diff --git a/spec/_ghpages/_gitignore.txt b/spec/_ghpages/_gitignore.txt new file mode 100644 index 000000000..4e7ddcaad --- /dev/null +++ b/spec/_ghpages/_gitignore.txt @@ -0,0 +1,36 @@ +#/ +# @license MIT +# +# Copyright (c) 2022 Python Data APIs Consortium. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#/ +# +# Note this file is not intended to be a .gitignore for the main branch, but to +# be copied into gh-pages branch. + +_site +build/ +doctrees/ +.vscode/ +node_modules/ +__pycache__/ +*.pyc +spec/**/generated/ +src/*.egg-info/ diff --git a/spec/_ghpages/index.html b/spec/_ghpages/index.html new file mode 100644 index 000000000..e209341a3 --- /dev/null +++ b/spec/_ghpages/index.html @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json new file mode 100644 index 000000000..5a6aa4692 --- /dev/null +++ b/spec/_ghpages/versions.json @@ -0,0 +1,5 @@ +{ + "2021.12": "2021.12", + "latest": "latest", + "draft": "draft" +} diff --git a/spec/draft/conf.py b/spec/draft/conf.py new file mode 100644 index 000000000..f3804e7ad --- /dev/null +++ b/spec/draft/conf.py @@ -0,0 +1,7 @@ +import sys + +from array_api_stubs import _draft as stubs_mod +from _array_api_conf import * + +release = "DRAFT" +sys.modules["array_api"] = stubs_mod diff --git a/spec/make.bat b/spec/make.bat deleted file mode 100644 index 2119f5109..000000000 --- a/spec/make.bat +++ /dev/null @@ -1,35 +0,0 @@ -@ECHO OFF - -pushd %~dp0 - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set SOURCEDIR=. -set BUILDDIR=_build - -if "%1" == "" goto help - -%SPHINXBUILD% >NUL 2>NUL -if errorlevel 9009 ( - echo. - echo.The 'sphinx-build' command was not found. Make sure you have Sphinx - echo.installed, then set the SPHINXBUILD environment variable to point - echo.to the full path of the 'sphinx-build' executable. Alternatively you - echo.may add the Sphinx directory to PATH. - echo. - echo.If you don't have Sphinx installed, grab it from - echo.http://sphinx-doc.org/ - exit /b 1 -) - -%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% -goto end - -:help -%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% - -:end -popd diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py new file mode 100644 index 000000000..82126be83 --- /dev/null +++ b/src/_array_api_conf.py @@ -0,0 +1,211 @@ +""" +Base config for all individual Sphinx docs in the array API repo. + +The array-api repo contains an individual Sphinx doc for each spec version, all +of which exist in ../spec/. This file is star-imported in the conf.py files of +these docs, allowing us to standardize configuration accross API versions. + +Every conf.py file which star-imports this should define + +* `release`, the str YYYY.MM release. Use "DRAFT" for the draft. +* `sys.modules['array_api']`, the stubs module to use for autodoc. +""" +import re + +import sphinx_material + +# -- Project information ----------------------------------------------------- + +project = 'Python array API standard' +copyright = '2020, Consortium for Python Data API Standards' +author = 'Consortium for Python Data API Standards' + +# -- General configuration --------------------------------------------------- + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'myst_parser', + 'sphinx.ext.extlinks', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx_markdown_tables', + 'sphinx_copybutton', + 'sphinx.ext.autosummary', + 'sphinx.ext.napoleon', + 'sphinx.ext.autodoc', +] + +autosummary_generate = True +autodoc_typehints = 'signature' +add_module_names = False +napoleon_custom_sections = [('Returns', 'params_style')] +default_role = 'code' + +# nitpicky = True makes Sphinx warn whenever a cross-reference target can't be +# found. +nitpicky = True +# autodoc wants to make cross-references for every type hint. But a lot of +# them don't actually refer to anything that we have a document for. +nitpick_ignore = [ + ('py:class', 'collections.abc.Sequence'), + ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), + ('py:class', "Union[int, float, Literal[inf, - inf]]"), + ('py:obj', "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]"), + ('py:obj', "typing.Union[int, float, typing.Literal[inf, - inf]]"), + ('py:class', 'enum.Enum'), + ('py:class', 'ellipsis'), +] +nitpick_ignore_regex = [ + ('py:class', '.*array'), + ('py:class', '.*device'), + ('py:class', '.*dtype'), + ('py:class', '.*NestedSequence'), + ('py:class', '.*SupportsBufferProtocol'), + ('py:class', '.*PyCapsule'), + ('py:class', '.*finfo_object'), + ('py:class', '.*iinfo_object'), +] +# In array_object.py we have to use aliased names for some types because they +# would otherwise refer back to method objects of array +autodoc_type_aliases = { + 'array': 'array', + 'Device': 'device', + 'Dtype': 'dtype', +} + +# Make autosummary show the signatures of functions in the tables using actual +# Python syntax. There's currently no supported way to do this, so we have to +# just patch out the function that processes the signatures. See +# https://github.com/sphinx-doc/sphinx/issues/10053. +import sphinx.ext.autosummary as autosummary_mod +if hasattr(autosummary_mod, '_module'): + # It's a sphinx deprecated module wrapper object + autosummary_mod = autosummary_mod._module +autosummary_mod.mangle_signature = lambda sig, max_chars=30: sig + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['../_templates'] + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# MyST options +myst_heading_anchors = 3 +myst_enable_extensions = ["colon_fence"] + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +extensions.append("sphinx_material") +html_theme_path = sphinx_material.html_theme_path() +html_context = sphinx_material.get_html_context() +html_theme = 'sphinx_material' + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['../_static'] + + +# -- Material theme options (see theme.conf for more information) ------------ +html_show_sourcelink = False +html_sidebars = { + "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] +} + +html_theme_options = { + + # Set the name of the project to appear in the navigation. + 'nav_title': f'Python array API standard', + + # Set you GA account ID to enable tracking + #'google_analytics_account': 'UA-XXXXX', + + # Specify a base_url used to generate sitemap.xml. If not + # specified, then no sitemap will be built. + #'base_url': 'https://project.github.io/project', + + # Set the color and the accent color (see + # https://material.io/design/color/the-color-system.html) + 'color_primary': 'indigo', + 'color_accent': 'green', + + # Set the repo location to get a badge with stats + #'repo_url': 'https://github.com/project/project/', + #'repo_name': 'Project', + + "html_minify": False, + "html_prettify": False, + "css_minify": True, + "logo_icon": "", + "repo_type": "github", + "touch_icon": "images/apple-icon-152x152.png", + "theme_color": "#2196f3", + "master_doc": False, + + # Visible levels of the global TOC; -1 means unlimited + 'globaltoc_depth': 2, + # If False, expand all TOC entries + 'globaltoc_collapse': True, + # If True, show hidden TOC entries + 'globaltoc_includehidden': True, + + "nav_links": [ + {"href": "index", "internal": True, "title": "Array API standard"}, + { + "href": "https://data-apis.org", + "internal": False, + "title": "Consortium for Python Data API Standards", + }, + ], + "heroes": { + "index": "A common API for array and tensor Python libraries", + #"customization": "Configuration options to personalize your site.", + }, + + "version_dropdown": True, + "version_json": "../versions.json", + "table_classes": ["plain"], +} + + +todo_include_todos = True +#html_favicon = "images/favicon.ico" + +html_use_index = True +html_domain_indices = True + +extlinks = { + "duref": ( + "http://docutils.sourceforge.net/docs/ref/rst/" "restructuredtext.html#%s", + "", + ), + "durole": ("http://docutils.sourceforge.net/docs/ref/rst/" "roles.html#%s", ""), + "dudir": ("http://docutils.sourceforge.net/docs/ref/rst/" "directives.html#%s", ""), + "pypa": ("https://packaging.python.org/%s", ""), +} + +# -- Prettify type hints ----------------------------------------------------- +r_type_prefix = re.compile(r"array_api(?:_stubs\._[a-z0-9_]+)?\._types\.") + +def process_signature(app, what, name, obj, options, signature, return_annotation): + if signature: +<<<<<<<< HEAD:spec/2021.12/conf.py + signature = signature.replace("signatures._types.", "") + if return_annotation: + return_annotation = return_annotation.replace("signatures._types.", "") +======== + signature = re.sub(r_type_prefix, "", signature) + if return_annotation: + return_annotation = re.sub(r_type_prefix, "", return_annotation) +>>>>>>>> bbd0384 (Squashed old all-versions work):src/_array_api_conf.py + return signature, return_annotation + +def setup(app): + app.connect("autodoc-process-signature", process_signature) diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py new file mode 100644 index 000000000..54614644a --- /dev/null +++ b/src/array_api_stubs/__init__.py @@ -0,0 +1,2 @@ +from . import _2021_12, _draft + From c280699be3460c10413c85fdb93d8997821a3ed6 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:45:24 +0000 Subject: [PATCH 359/551] Move 2022.12 docs into respective draft folders --- spec/{ => draft}/2022.12/API_specification/array_object.rst | 0 spec/{ => draft}/2022.12/API_specification/broadcasting.rst | 0 spec/{ => draft}/2022.12/API_specification/constants.rst | 0 spec/{ => draft}/2022.12/API_specification/creation_functions.rst | 0 .../{ => draft}/2022.12/API_specification/data_type_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/data_types.rst | 0 .../2022.12/API_specification/elementwise_functions.rst | 0 .../2022.12/API_specification/function_and_method_signatures.rst | 0 spec/{ => draft}/2022.12/API_specification/index.rst | 0 spec/{ => draft}/2022.12/API_specification/indexing.rst | 0 spec/{ => draft}/2022.12/API_specification/indexing_functions.rst | 0 .../2022.12/API_specification/linear_algebra_functions.rst | 0 .../2022.12/API_specification/manipulation_functions.rst | 0 .../{ => draft}/2022.12/API_specification/searching_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/set_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/sorting_functions.rst | 0 .../2022.12/API_specification/statistical_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/type_promotion.rst | 0 spec/{ => draft}/2022.12/API_specification/utility_functions.rst | 0 spec/{ => draft}/2022.12/API_specification/version.rst | 0 spec/{ => draft}/2022.12/assumptions.md | 0 spec/{ => draft}/2022.12/benchmark_suite.md | 0 spec/{ => draft}/2022.12/changelog.rst | 0 spec/{ => draft}/2022.12/design_topics/C_API.rst | 0 spec/{ => draft}/2022.12/design_topics/accuracy.rst | 0 spec/{ => draft}/2022.12/design_topics/complex_numbers.rst | 0 .../2022.12/design_topics/copies_views_and_mutation.rst | 0 .../2022.12/design_topics/data_dependent_output_shapes.rst | 0 spec/{ => draft}/2022.12/design_topics/data_interchange.rst | 0 spec/{ => draft}/2022.12/design_topics/device_support.rst | 0 spec/{ => draft}/2022.12/design_topics/index.rst | 0 spec/{ => draft}/2022.12/design_topics/parallelism.rst | 0 spec/{ => draft}/2022.12/design_topics/static_typing.rst | 0 .../2022.12/extensions/fourier_transform_functions.rst | 0 spec/{ => draft}/2022.12/extensions/index.rst | 0 spec/{ => draft}/2022.12/extensions/linear_algebra_functions.rst | 0 spec/{ => draft}/2022.12/future_API_evolution.md | 0 spec/{ => draft}/2022.12/index.rst | 0 spec/{ => draft}/2022.12/purpose_and_scope.md | 0 spec/{ => draft}/2022.12/usage_data.md | 0 spec/{ => draft}/2022.12/use_cases.md | 0 spec/{ => draft}/2022.12/verification_test_suite.md | 0 src/array_api_stubs/{_2022_12 => _draft}/__init__.py | 0 src/array_api_stubs/{_2022_12 => _draft}/_types.py | 0 src/array_api_stubs/{_2022_12 => _draft}/array_object.py | 0 src/array_api_stubs/{_2022_12 => _draft}/constants.py | 0 src/array_api_stubs/{_2022_12 => _draft}/creation_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/data_type_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/data_types.py | 0 src/array_api_stubs/{_2022_12 => _draft}/elementwise_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/fft.py | 0 src/array_api_stubs/{_2022_12 => _draft}/indexing_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/linalg.py | 0 .../{_2022_12 => _draft}/linear_algebra_functions.py | 0 .../{_2022_12 => _draft}/manipulation_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/searching_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/set_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/sorting_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/statistical_functions.py | 0 src/array_api_stubs/{_2022_12 => _draft}/utility_functions.py | 0 60 files changed, 0 insertions(+), 0 deletions(-) rename spec/{ => draft}/2022.12/API_specification/array_object.rst (100%) rename spec/{ => draft}/2022.12/API_specification/broadcasting.rst (100%) rename spec/{ => draft}/2022.12/API_specification/constants.rst (100%) rename spec/{ => draft}/2022.12/API_specification/creation_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/data_type_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/data_types.rst (100%) rename spec/{ => draft}/2022.12/API_specification/elementwise_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/function_and_method_signatures.rst (100%) rename spec/{ => draft}/2022.12/API_specification/index.rst (100%) rename spec/{ => draft}/2022.12/API_specification/indexing.rst (100%) rename spec/{ => draft}/2022.12/API_specification/indexing_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/linear_algebra_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/manipulation_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/searching_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/set_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/sorting_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/statistical_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/type_promotion.rst (100%) rename spec/{ => draft}/2022.12/API_specification/utility_functions.rst (100%) rename spec/{ => draft}/2022.12/API_specification/version.rst (100%) rename spec/{ => draft}/2022.12/assumptions.md (100%) rename spec/{ => draft}/2022.12/benchmark_suite.md (100%) rename spec/{ => draft}/2022.12/changelog.rst (100%) rename spec/{ => draft}/2022.12/design_topics/C_API.rst (100%) rename spec/{ => draft}/2022.12/design_topics/accuracy.rst (100%) rename spec/{ => draft}/2022.12/design_topics/complex_numbers.rst (100%) rename spec/{ => draft}/2022.12/design_topics/copies_views_and_mutation.rst (100%) rename spec/{ => draft}/2022.12/design_topics/data_dependent_output_shapes.rst (100%) rename spec/{ => draft}/2022.12/design_topics/data_interchange.rst (100%) rename spec/{ => draft}/2022.12/design_topics/device_support.rst (100%) rename spec/{ => draft}/2022.12/design_topics/index.rst (100%) rename spec/{ => draft}/2022.12/design_topics/parallelism.rst (100%) rename spec/{ => draft}/2022.12/design_topics/static_typing.rst (100%) rename spec/{ => draft}/2022.12/extensions/fourier_transform_functions.rst (100%) rename spec/{ => draft}/2022.12/extensions/index.rst (100%) rename spec/{ => draft}/2022.12/extensions/linear_algebra_functions.rst (100%) rename spec/{ => draft}/2022.12/future_API_evolution.md (100%) rename spec/{ => draft}/2022.12/index.rst (100%) rename spec/{ => draft}/2022.12/purpose_and_scope.md (100%) rename spec/{ => draft}/2022.12/usage_data.md (100%) rename spec/{ => draft}/2022.12/use_cases.md (100%) rename spec/{ => draft}/2022.12/verification_test_suite.md (100%) rename src/array_api_stubs/{_2022_12 => _draft}/__init__.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/_types.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/array_object.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/constants.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/creation_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/data_type_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/data_types.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/elementwise_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/fft.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/indexing_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/linalg.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/linear_algebra_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/manipulation_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/searching_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/set_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/sorting_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/statistical_functions.py (100%) rename src/array_api_stubs/{_2022_12 => _draft}/utility_functions.py (100%) diff --git a/spec/2022.12/API_specification/array_object.rst b/spec/draft/2022.12/API_specification/array_object.rst similarity index 100% rename from spec/2022.12/API_specification/array_object.rst rename to spec/draft/2022.12/API_specification/array_object.rst diff --git a/spec/2022.12/API_specification/broadcasting.rst b/spec/draft/2022.12/API_specification/broadcasting.rst similarity index 100% rename from spec/2022.12/API_specification/broadcasting.rst rename to spec/draft/2022.12/API_specification/broadcasting.rst diff --git a/spec/2022.12/API_specification/constants.rst b/spec/draft/2022.12/API_specification/constants.rst similarity index 100% rename from spec/2022.12/API_specification/constants.rst rename to spec/draft/2022.12/API_specification/constants.rst diff --git a/spec/2022.12/API_specification/creation_functions.rst b/spec/draft/2022.12/API_specification/creation_functions.rst similarity index 100% rename from spec/2022.12/API_specification/creation_functions.rst rename to spec/draft/2022.12/API_specification/creation_functions.rst diff --git a/spec/2022.12/API_specification/data_type_functions.rst b/spec/draft/2022.12/API_specification/data_type_functions.rst similarity index 100% rename from spec/2022.12/API_specification/data_type_functions.rst rename to spec/draft/2022.12/API_specification/data_type_functions.rst diff --git a/spec/2022.12/API_specification/data_types.rst b/spec/draft/2022.12/API_specification/data_types.rst similarity index 100% rename from spec/2022.12/API_specification/data_types.rst rename to spec/draft/2022.12/API_specification/data_types.rst diff --git a/spec/2022.12/API_specification/elementwise_functions.rst b/spec/draft/2022.12/API_specification/elementwise_functions.rst similarity index 100% rename from spec/2022.12/API_specification/elementwise_functions.rst rename to spec/draft/2022.12/API_specification/elementwise_functions.rst diff --git a/spec/2022.12/API_specification/function_and_method_signatures.rst b/spec/draft/2022.12/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/2022.12/API_specification/function_and_method_signatures.rst rename to spec/draft/2022.12/API_specification/function_and_method_signatures.rst diff --git a/spec/2022.12/API_specification/index.rst b/spec/draft/2022.12/API_specification/index.rst similarity index 100% rename from spec/2022.12/API_specification/index.rst rename to spec/draft/2022.12/API_specification/index.rst diff --git a/spec/2022.12/API_specification/indexing.rst b/spec/draft/2022.12/API_specification/indexing.rst similarity index 100% rename from spec/2022.12/API_specification/indexing.rst rename to spec/draft/2022.12/API_specification/indexing.rst diff --git a/spec/2022.12/API_specification/indexing_functions.rst b/spec/draft/2022.12/API_specification/indexing_functions.rst similarity index 100% rename from spec/2022.12/API_specification/indexing_functions.rst rename to spec/draft/2022.12/API_specification/indexing_functions.rst diff --git a/spec/2022.12/API_specification/linear_algebra_functions.rst b/spec/draft/2022.12/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/2022.12/API_specification/linear_algebra_functions.rst rename to spec/draft/2022.12/API_specification/linear_algebra_functions.rst diff --git a/spec/2022.12/API_specification/manipulation_functions.rst b/spec/draft/2022.12/API_specification/manipulation_functions.rst similarity index 100% rename from spec/2022.12/API_specification/manipulation_functions.rst rename to spec/draft/2022.12/API_specification/manipulation_functions.rst diff --git a/spec/2022.12/API_specification/searching_functions.rst b/spec/draft/2022.12/API_specification/searching_functions.rst similarity index 100% rename from spec/2022.12/API_specification/searching_functions.rst rename to spec/draft/2022.12/API_specification/searching_functions.rst diff --git a/spec/2022.12/API_specification/set_functions.rst b/spec/draft/2022.12/API_specification/set_functions.rst similarity index 100% rename from spec/2022.12/API_specification/set_functions.rst rename to spec/draft/2022.12/API_specification/set_functions.rst diff --git a/spec/2022.12/API_specification/sorting_functions.rst b/spec/draft/2022.12/API_specification/sorting_functions.rst similarity index 100% rename from spec/2022.12/API_specification/sorting_functions.rst rename to spec/draft/2022.12/API_specification/sorting_functions.rst diff --git a/spec/2022.12/API_specification/statistical_functions.rst b/spec/draft/2022.12/API_specification/statistical_functions.rst similarity index 100% rename from spec/2022.12/API_specification/statistical_functions.rst rename to spec/draft/2022.12/API_specification/statistical_functions.rst diff --git a/spec/2022.12/API_specification/type_promotion.rst b/spec/draft/2022.12/API_specification/type_promotion.rst similarity index 100% rename from spec/2022.12/API_specification/type_promotion.rst rename to spec/draft/2022.12/API_specification/type_promotion.rst diff --git a/spec/2022.12/API_specification/utility_functions.rst b/spec/draft/2022.12/API_specification/utility_functions.rst similarity index 100% rename from spec/2022.12/API_specification/utility_functions.rst rename to spec/draft/2022.12/API_specification/utility_functions.rst diff --git a/spec/2022.12/API_specification/version.rst b/spec/draft/2022.12/API_specification/version.rst similarity index 100% rename from spec/2022.12/API_specification/version.rst rename to spec/draft/2022.12/API_specification/version.rst diff --git a/spec/2022.12/assumptions.md b/spec/draft/2022.12/assumptions.md similarity index 100% rename from spec/2022.12/assumptions.md rename to spec/draft/2022.12/assumptions.md diff --git a/spec/2022.12/benchmark_suite.md b/spec/draft/2022.12/benchmark_suite.md similarity index 100% rename from spec/2022.12/benchmark_suite.md rename to spec/draft/2022.12/benchmark_suite.md diff --git a/spec/2022.12/changelog.rst b/spec/draft/2022.12/changelog.rst similarity index 100% rename from spec/2022.12/changelog.rst rename to spec/draft/2022.12/changelog.rst diff --git a/spec/2022.12/design_topics/C_API.rst b/spec/draft/2022.12/design_topics/C_API.rst similarity index 100% rename from spec/2022.12/design_topics/C_API.rst rename to spec/draft/2022.12/design_topics/C_API.rst diff --git a/spec/2022.12/design_topics/accuracy.rst b/spec/draft/2022.12/design_topics/accuracy.rst similarity index 100% rename from spec/2022.12/design_topics/accuracy.rst rename to spec/draft/2022.12/design_topics/accuracy.rst diff --git a/spec/2022.12/design_topics/complex_numbers.rst b/spec/draft/2022.12/design_topics/complex_numbers.rst similarity index 100% rename from spec/2022.12/design_topics/complex_numbers.rst rename to spec/draft/2022.12/design_topics/complex_numbers.rst diff --git a/spec/2022.12/design_topics/copies_views_and_mutation.rst b/spec/draft/2022.12/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/2022.12/design_topics/copies_views_and_mutation.rst rename to spec/draft/2022.12/design_topics/copies_views_and_mutation.rst diff --git a/spec/2022.12/design_topics/data_dependent_output_shapes.rst b/spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/2022.12/design_topics/data_dependent_output_shapes.rst rename to spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst diff --git a/spec/2022.12/design_topics/data_interchange.rst b/spec/draft/2022.12/design_topics/data_interchange.rst similarity index 100% rename from spec/2022.12/design_topics/data_interchange.rst rename to spec/draft/2022.12/design_topics/data_interchange.rst diff --git a/spec/2022.12/design_topics/device_support.rst b/spec/draft/2022.12/design_topics/device_support.rst similarity index 100% rename from spec/2022.12/design_topics/device_support.rst rename to spec/draft/2022.12/design_topics/device_support.rst diff --git a/spec/2022.12/design_topics/index.rst b/spec/draft/2022.12/design_topics/index.rst similarity index 100% rename from spec/2022.12/design_topics/index.rst rename to spec/draft/2022.12/design_topics/index.rst diff --git a/spec/2022.12/design_topics/parallelism.rst b/spec/draft/2022.12/design_topics/parallelism.rst similarity index 100% rename from spec/2022.12/design_topics/parallelism.rst rename to spec/draft/2022.12/design_topics/parallelism.rst diff --git a/spec/2022.12/design_topics/static_typing.rst b/spec/draft/2022.12/design_topics/static_typing.rst similarity index 100% rename from spec/2022.12/design_topics/static_typing.rst rename to spec/draft/2022.12/design_topics/static_typing.rst diff --git a/spec/2022.12/extensions/fourier_transform_functions.rst b/spec/draft/2022.12/extensions/fourier_transform_functions.rst similarity index 100% rename from spec/2022.12/extensions/fourier_transform_functions.rst rename to spec/draft/2022.12/extensions/fourier_transform_functions.rst diff --git a/spec/2022.12/extensions/index.rst b/spec/draft/2022.12/extensions/index.rst similarity index 100% rename from spec/2022.12/extensions/index.rst rename to spec/draft/2022.12/extensions/index.rst diff --git a/spec/2022.12/extensions/linear_algebra_functions.rst b/spec/draft/2022.12/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/2022.12/extensions/linear_algebra_functions.rst rename to spec/draft/2022.12/extensions/linear_algebra_functions.rst diff --git a/spec/2022.12/future_API_evolution.md b/spec/draft/2022.12/future_API_evolution.md similarity index 100% rename from spec/2022.12/future_API_evolution.md rename to spec/draft/2022.12/future_API_evolution.md diff --git a/spec/2022.12/index.rst b/spec/draft/2022.12/index.rst similarity index 100% rename from spec/2022.12/index.rst rename to spec/draft/2022.12/index.rst diff --git a/spec/2022.12/purpose_and_scope.md b/spec/draft/2022.12/purpose_and_scope.md similarity index 100% rename from spec/2022.12/purpose_and_scope.md rename to spec/draft/2022.12/purpose_and_scope.md diff --git a/spec/2022.12/usage_data.md b/spec/draft/2022.12/usage_data.md similarity index 100% rename from spec/2022.12/usage_data.md rename to spec/draft/2022.12/usage_data.md diff --git a/spec/2022.12/use_cases.md b/spec/draft/2022.12/use_cases.md similarity index 100% rename from spec/2022.12/use_cases.md rename to spec/draft/2022.12/use_cases.md diff --git a/spec/2022.12/verification_test_suite.md b/spec/draft/2022.12/verification_test_suite.md similarity index 100% rename from spec/2022.12/verification_test_suite.md rename to spec/draft/2022.12/verification_test_suite.md diff --git a/src/array_api_stubs/_2022_12/__init__.py b/src/array_api_stubs/_draft/__init__.py similarity index 100% rename from src/array_api_stubs/_2022_12/__init__.py rename to src/array_api_stubs/_draft/__init__.py diff --git a/src/array_api_stubs/_2022_12/_types.py b/src/array_api_stubs/_draft/_types.py similarity index 100% rename from src/array_api_stubs/_2022_12/_types.py rename to src/array_api_stubs/_draft/_types.py diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_draft/array_object.py similarity index 100% rename from src/array_api_stubs/_2022_12/array_object.py rename to src/array_api_stubs/_draft/array_object.py diff --git a/src/array_api_stubs/_2022_12/constants.py b/src/array_api_stubs/_draft/constants.py similarity index 100% rename from src/array_api_stubs/_2022_12/constants.py rename to src/array_api_stubs/_draft/constants.py diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/creation_functions.py rename to src/array_api_stubs/_draft/creation_functions.py diff --git a/src/array_api_stubs/_2022_12/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/data_type_functions.py rename to src/array_api_stubs/_draft/data_type_functions.py diff --git a/src/array_api_stubs/_2022_12/data_types.py b/src/array_api_stubs/_draft/data_types.py similarity index 100% rename from src/array_api_stubs/_2022_12/data_types.py rename to src/array_api_stubs/_draft/data_types.py diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/elementwise_functions.py rename to src/array_api_stubs/_draft/elementwise_functions.py diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_draft/fft.py similarity index 100% rename from src/array_api_stubs/_2022_12/fft.py rename to src/array_api_stubs/_draft/fft.py diff --git a/src/array_api_stubs/_2022_12/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/indexing_functions.py rename to src/array_api_stubs/_draft/indexing_functions.py diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_draft/linalg.py similarity index 100% rename from src/array_api_stubs/_2022_12/linalg.py rename to src/array_api_stubs/_draft/linalg.py diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/linear_algebra_functions.py rename to src/array_api_stubs/_draft/linear_algebra_functions.py diff --git a/src/array_api_stubs/_2022_12/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/manipulation_functions.py rename to src/array_api_stubs/_draft/manipulation_functions.py diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/searching_functions.py rename to src/array_api_stubs/_draft/searching_functions.py diff --git a/src/array_api_stubs/_2022_12/set_functions.py b/src/array_api_stubs/_draft/set_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/set_functions.py rename to src/array_api_stubs/_draft/set_functions.py diff --git a/src/array_api_stubs/_2022_12/sorting_functions.py b/src/array_api_stubs/_draft/sorting_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/sorting_functions.py rename to src/array_api_stubs/_draft/sorting_functions.py diff --git a/src/array_api_stubs/_2022_12/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/statistical_functions.py rename to src/array_api_stubs/_draft/statistical_functions.py diff --git a/src/array_api_stubs/_2022_12/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py similarity index 100% rename from src/array_api_stubs/_2022_12/utility_functions.py rename to src/array_api_stubs/_draft/utility_functions.py From 988f2f86bea64d565857dc05e3feb625fd7729fb Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:46:10 +0000 Subject: [PATCH 360/551] Empty commit for 2022.12 docs From c5afa3897acb03a714b170ee148271de95ea49d8 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Thu, 5 Jan 2023 13:52:08 +0000 Subject: [PATCH 361/551] Fix erroneous draft spec folder structure --- spec/draft/{2022.12 => }/API_specification/array_object.rst | 0 spec/draft/{2022.12 => }/API_specification/broadcasting.rst | 0 spec/draft/{2022.12 => }/API_specification/constants.rst | 0 spec/draft/{2022.12 => }/API_specification/creation_functions.rst | 0 .../draft/{2022.12 => }/API_specification/data_type_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/data_types.rst | 0 .../{2022.12 => }/API_specification/elementwise_functions.rst | 0 .../API_specification/function_and_method_signatures.rst | 0 spec/draft/{2022.12 => }/API_specification/index.rst | 0 spec/draft/{2022.12 => }/API_specification/indexing.rst | 0 spec/draft/{2022.12 => }/API_specification/indexing_functions.rst | 0 .../{2022.12 => }/API_specification/linear_algebra_functions.rst | 0 .../{2022.12 => }/API_specification/manipulation_functions.rst | 0 .../draft/{2022.12 => }/API_specification/searching_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/set_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/sorting_functions.rst | 0 .../{2022.12 => }/API_specification/statistical_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/type_promotion.rst | 0 spec/draft/{2022.12 => }/API_specification/utility_functions.rst | 0 spec/draft/{2022.12 => }/API_specification/version.rst | 0 spec/draft/{2022.12 => }/assumptions.md | 0 spec/draft/{2022.12 => }/benchmark_suite.md | 0 spec/draft/{2022.12 => }/changelog.rst | 0 spec/draft/{2022.12 => }/design_topics/C_API.rst | 0 spec/draft/{2022.12 => }/design_topics/accuracy.rst | 0 spec/draft/{2022.12 => }/design_topics/complex_numbers.rst | 0 .../{2022.12 => }/design_topics/copies_views_and_mutation.rst | 0 .../{2022.12 => }/design_topics/data_dependent_output_shapes.rst | 0 spec/draft/{2022.12 => }/design_topics/data_interchange.rst | 0 spec/draft/{2022.12 => }/design_topics/device_support.rst | 0 spec/draft/{2022.12 => }/design_topics/index.rst | 0 spec/draft/{2022.12 => }/design_topics/parallelism.rst | 0 spec/draft/{2022.12 => }/design_topics/static_typing.rst | 0 .../{2022.12 => }/extensions/fourier_transform_functions.rst | 0 spec/draft/{2022.12 => }/extensions/index.rst | 0 spec/draft/{2022.12 => }/extensions/linear_algebra_functions.rst | 0 spec/draft/{2022.12 => }/future_API_evolution.md | 0 spec/draft/{2022.12 => }/index.rst | 0 spec/draft/{2022.12 => }/purpose_and_scope.md | 0 spec/draft/{2022.12 => }/usage_data.md | 0 spec/draft/{2022.12 => }/use_cases.md | 0 spec/draft/{2022.12 => }/verification_test_suite.md | 0 42 files changed, 0 insertions(+), 0 deletions(-) rename spec/draft/{2022.12 => }/API_specification/array_object.rst (100%) rename spec/draft/{2022.12 => }/API_specification/broadcasting.rst (100%) rename spec/draft/{2022.12 => }/API_specification/constants.rst (100%) rename spec/draft/{2022.12 => }/API_specification/creation_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/data_type_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/data_types.rst (100%) rename spec/draft/{2022.12 => }/API_specification/elementwise_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/function_and_method_signatures.rst (100%) rename spec/draft/{2022.12 => }/API_specification/index.rst (100%) rename spec/draft/{2022.12 => }/API_specification/indexing.rst (100%) rename spec/draft/{2022.12 => }/API_specification/indexing_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/linear_algebra_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/manipulation_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/searching_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/set_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/sorting_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/statistical_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/type_promotion.rst (100%) rename spec/draft/{2022.12 => }/API_specification/utility_functions.rst (100%) rename spec/draft/{2022.12 => }/API_specification/version.rst (100%) rename spec/draft/{2022.12 => }/assumptions.md (100%) rename spec/draft/{2022.12 => }/benchmark_suite.md (100%) rename spec/draft/{2022.12 => }/changelog.rst (100%) rename spec/draft/{2022.12 => }/design_topics/C_API.rst (100%) rename spec/draft/{2022.12 => }/design_topics/accuracy.rst (100%) rename spec/draft/{2022.12 => }/design_topics/complex_numbers.rst (100%) rename spec/draft/{2022.12 => }/design_topics/copies_views_and_mutation.rst (100%) rename spec/draft/{2022.12 => }/design_topics/data_dependent_output_shapes.rst (100%) rename spec/draft/{2022.12 => }/design_topics/data_interchange.rst (100%) rename spec/draft/{2022.12 => }/design_topics/device_support.rst (100%) rename spec/draft/{2022.12 => }/design_topics/index.rst (100%) rename spec/draft/{2022.12 => }/design_topics/parallelism.rst (100%) rename spec/draft/{2022.12 => }/design_topics/static_typing.rst (100%) rename spec/draft/{2022.12 => }/extensions/fourier_transform_functions.rst (100%) rename spec/draft/{2022.12 => }/extensions/index.rst (100%) rename spec/draft/{2022.12 => }/extensions/linear_algebra_functions.rst (100%) rename spec/draft/{2022.12 => }/future_API_evolution.md (100%) rename spec/draft/{2022.12 => }/index.rst (100%) rename spec/draft/{2022.12 => }/purpose_and_scope.md (100%) rename spec/draft/{2022.12 => }/usage_data.md (100%) rename spec/draft/{2022.12 => }/use_cases.md (100%) rename spec/draft/{2022.12 => }/verification_test_suite.md (100%) diff --git a/spec/draft/2022.12/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst similarity index 100% rename from spec/draft/2022.12/API_specification/array_object.rst rename to spec/draft/API_specification/array_object.rst diff --git a/spec/draft/2022.12/API_specification/broadcasting.rst b/spec/draft/API_specification/broadcasting.rst similarity index 100% rename from spec/draft/2022.12/API_specification/broadcasting.rst rename to spec/draft/API_specification/broadcasting.rst diff --git a/spec/draft/2022.12/API_specification/constants.rst b/spec/draft/API_specification/constants.rst similarity index 100% rename from spec/draft/2022.12/API_specification/constants.rst rename to spec/draft/API_specification/constants.rst diff --git a/spec/draft/2022.12/API_specification/creation_functions.rst b/spec/draft/API_specification/creation_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/creation_functions.rst rename to spec/draft/API_specification/creation_functions.rst diff --git a/spec/draft/2022.12/API_specification/data_type_functions.rst b/spec/draft/API_specification/data_type_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/data_type_functions.rst rename to spec/draft/API_specification/data_type_functions.rst diff --git a/spec/draft/2022.12/API_specification/data_types.rst b/spec/draft/API_specification/data_types.rst similarity index 100% rename from spec/draft/2022.12/API_specification/data_types.rst rename to spec/draft/API_specification/data_types.rst diff --git a/spec/draft/2022.12/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/elementwise_functions.rst rename to spec/draft/API_specification/elementwise_functions.rst diff --git a/spec/draft/2022.12/API_specification/function_and_method_signatures.rst b/spec/draft/API_specification/function_and_method_signatures.rst similarity index 100% rename from spec/draft/2022.12/API_specification/function_and_method_signatures.rst rename to spec/draft/API_specification/function_and_method_signatures.rst diff --git a/spec/draft/2022.12/API_specification/index.rst b/spec/draft/API_specification/index.rst similarity index 100% rename from spec/draft/2022.12/API_specification/index.rst rename to spec/draft/API_specification/index.rst diff --git a/spec/draft/2022.12/API_specification/indexing.rst b/spec/draft/API_specification/indexing.rst similarity index 100% rename from spec/draft/2022.12/API_specification/indexing.rst rename to spec/draft/API_specification/indexing.rst diff --git a/spec/draft/2022.12/API_specification/indexing_functions.rst b/spec/draft/API_specification/indexing_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/indexing_functions.rst rename to spec/draft/API_specification/indexing_functions.rst diff --git a/spec/draft/2022.12/API_specification/linear_algebra_functions.rst b/spec/draft/API_specification/linear_algebra_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/linear_algebra_functions.rst rename to spec/draft/API_specification/linear_algebra_functions.rst diff --git a/spec/draft/2022.12/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/manipulation_functions.rst rename to spec/draft/API_specification/manipulation_functions.rst diff --git a/spec/draft/2022.12/API_specification/searching_functions.rst b/spec/draft/API_specification/searching_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/searching_functions.rst rename to spec/draft/API_specification/searching_functions.rst diff --git a/spec/draft/2022.12/API_specification/set_functions.rst b/spec/draft/API_specification/set_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/set_functions.rst rename to spec/draft/API_specification/set_functions.rst diff --git a/spec/draft/2022.12/API_specification/sorting_functions.rst b/spec/draft/API_specification/sorting_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/sorting_functions.rst rename to spec/draft/API_specification/sorting_functions.rst diff --git a/spec/draft/2022.12/API_specification/statistical_functions.rst b/spec/draft/API_specification/statistical_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/statistical_functions.rst rename to spec/draft/API_specification/statistical_functions.rst diff --git a/spec/draft/2022.12/API_specification/type_promotion.rst b/spec/draft/API_specification/type_promotion.rst similarity index 100% rename from spec/draft/2022.12/API_specification/type_promotion.rst rename to spec/draft/API_specification/type_promotion.rst diff --git a/spec/draft/2022.12/API_specification/utility_functions.rst b/spec/draft/API_specification/utility_functions.rst similarity index 100% rename from spec/draft/2022.12/API_specification/utility_functions.rst rename to spec/draft/API_specification/utility_functions.rst diff --git a/spec/draft/2022.12/API_specification/version.rst b/spec/draft/API_specification/version.rst similarity index 100% rename from spec/draft/2022.12/API_specification/version.rst rename to spec/draft/API_specification/version.rst diff --git a/spec/draft/2022.12/assumptions.md b/spec/draft/assumptions.md similarity index 100% rename from spec/draft/2022.12/assumptions.md rename to spec/draft/assumptions.md diff --git a/spec/draft/2022.12/benchmark_suite.md b/spec/draft/benchmark_suite.md similarity index 100% rename from spec/draft/2022.12/benchmark_suite.md rename to spec/draft/benchmark_suite.md diff --git a/spec/draft/2022.12/changelog.rst b/spec/draft/changelog.rst similarity index 100% rename from spec/draft/2022.12/changelog.rst rename to spec/draft/changelog.rst diff --git a/spec/draft/2022.12/design_topics/C_API.rst b/spec/draft/design_topics/C_API.rst similarity index 100% rename from spec/draft/2022.12/design_topics/C_API.rst rename to spec/draft/design_topics/C_API.rst diff --git a/spec/draft/2022.12/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst similarity index 100% rename from spec/draft/2022.12/design_topics/accuracy.rst rename to spec/draft/design_topics/accuracy.rst diff --git a/spec/draft/2022.12/design_topics/complex_numbers.rst b/spec/draft/design_topics/complex_numbers.rst similarity index 100% rename from spec/draft/2022.12/design_topics/complex_numbers.rst rename to spec/draft/design_topics/complex_numbers.rst diff --git a/spec/draft/2022.12/design_topics/copies_views_and_mutation.rst b/spec/draft/design_topics/copies_views_and_mutation.rst similarity index 100% rename from spec/draft/2022.12/design_topics/copies_views_and_mutation.rst rename to spec/draft/design_topics/copies_views_and_mutation.rst diff --git a/spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst b/spec/draft/design_topics/data_dependent_output_shapes.rst similarity index 100% rename from spec/draft/2022.12/design_topics/data_dependent_output_shapes.rst rename to spec/draft/design_topics/data_dependent_output_shapes.rst diff --git a/spec/draft/2022.12/design_topics/data_interchange.rst b/spec/draft/design_topics/data_interchange.rst similarity index 100% rename from spec/draft/2022.12/design_topics/data_interchange.rst rename to spec/draft/design_topics/data_interchange.rst diff --git a/spec/draft/2022.12/design_topics/device_support.rst b/spec/draft/design_topics/device_support.rst similarity index 100% rename from spec/draft/2022.12/design_topics/device_support.rst rename to spec/draft/design_topics/device_support.rst diff --git a/spec/draft/2022.12/design_topics/index.rst b/spec/draft/design_topics/index.rst similarity index 100% rename from spec/draft/2022.12/design_topics/index.rst rename to spec/draft/design_topics/index.rst diff --git a/spec/draft/2022.12/design_topics/parallelism.rst b/spec/draft/design_topics/parallelism.rst similarity index 100% rename from spec/draft/2022.12/design_topics/parallelism.rst rename to spec/draft/design_topics/parallelism.rst diff --git a/spec/draft/2022.12/design_topics/static_typing.rst b/spec/draft/design_topics/static_typing.rst similarity index 100% rename from spec/draft/2022.12/design_topics/static_typing.rst rename to spec/draft/design_topics/static_typing.rst diff --git a/spec/draft/2022.12/extensions/fourier_transform_functions.rst b/spec/draft/extensions/fourier_transform_functions.rst similarity index 100% rename from spec/draft/2022.12/extensions/fourier_transform_functions.rst rename to spec/draft/extensions/fourier_transform_functions.rst diff --git a/spec/draft/2022.12/extensions/index.rst b/spec/draft/extensions/index.rst similarity index 100% rename from spec/draft/2022.12/extensions/index.rst rename to spec/draft/extensions/index.rst diff --git a/spec/draft/2022.12/extensions/linear_algebra_functions.rst b/spec/draft/extensions/linear_algebra_functions.rst similarity index 100% rename from spec/draft/2022.12/extensions/linear_algebra_functions.rst rename to spec/draft/extensions/linear_algebra_functions.rst diff --git a/spec/draft/2022.12/future_API_evolution.md b/spec/draft/future_API_evolution.md similarity index 100% rename from spec/draft/2022.12/future_API_evolution.md rename to spec/draft/future_API_evolution.md diff --git a/spec/draft/2022.12/index.rst b/spec/draft/index.rst similarity index 100% rename from spec/draft/2022.12/index.rst rename to spec/draft/index.rst diff --git a/spec/draft/2022.12/purpose_and_scope.md b/spec/draft/purpose_and_scope.md similarity index 100% rename from spec/draft/2022.12/purpose_and_scope.md rename to spec/draft/purpose_and_scope.md diff --git a/spec/draft/2022.12/usage_data.md b/spec/draft/usage_data.md similarity index 100% rename from spec/draft/2022.12/usage_data.md rename to spec/draft/usage_data.md diff --git a/spec/draft/2022.12/use_cases.md b/spec/draft/use_cases.md similarity index 100% rename from spec/draft/2022.12/use_cases.md rename to spec/draft/use_cases.md diff --git a/spec/draft/2022.12/verification_test_suite.md b/spec/draft/verification_test_suite.md similarity index 100% rename from spec/draft/2022.12/verification_test_suite.md rename to spec/draft/verification_test_suite.md From c74b390417c056e67cba31debb08920edd3f73d1 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 13:10:26 +0000 Subject: [PATCH 362/551] Resolve accidental merge artifact --- src/_array_api_conf.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 82126be83..161590fea 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -196,15 +196,9 @@ def process_signature(app, what, name, obj, options, signature, return_annotation): if signature: -<<<<<<<< HEAD:spec/2021.12/conf.py - signature = signature.replace("signatures._types.", "") - if return_annotation: - return_annotation = return_annotation.replace("signatures._types.", "") -======== signature = re.sub(r_type_prefix, "", signature) if return_annotation: return_annotation = re.sub(r_type_prefix, "", return_annotation) ->>>>>>>> bbd0384 (Squashed old all-versions work):src/_array_api_conf.py return signature, return_annotation def setup(app): From ada910275c2105ad3cf1aa4a3d7deb13cd6524a0 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 14:06:02 +0000 Subject: [PATCH 363/551] Fix `2021.12` building --- .../API_specification/array_object.rst | 2 +- spec/2021.12/API_specification/constants.rst | 2 +- .../API_specification/creation_functions.rst | 2 +- .../API_specification/data_type_functions.rst | 2 +- spec/2021.12/API_specification/data_types.rst | 2 +- .../elementwise_functions.rst | 2 +- spec/2021.12/API_specification/indexing.rst | 4 +- .../linear_algebra_functions.rst | 2 +- .../manipulation_functions.rst | 2 +- .../API_specification/searching_functions.rst | 2 +- .../API_specification/set_functions.rst | 2 +- .../API_specification/sorting_functions.rst | 2 +- .../statistical_functions.rst | 2 +- .../API_specification/utility_functions.rst | 2 +- spec/2021.12/conf.py | 207 +----------------- .../extensions/linear_algebra_functions.rst | 2 +- spec/2022.12/API_specification/data_types.rst | 4 +- src/array_api_stubs/_2021_12/__init__.py | 22 ++ src/array_api_stubs/_2021_12/array_object.py | 50 ++--- .../_2021_12/creation_functions.py | 2 +- src/array_api_stubs/_2021_12/linalg.py | 8 +- src/array_api_stubs/_2022_12/__init__.py | 2 +- src/array_api_stubs/_draft/__init__.py | 2 +- 23 files changed, 76 insertions(+), 253 deletions(-) diff --git a/spec/2021.12/API_specification/array_object.rst b/spec/2021.12/API_specification/array_object.rst index 55a8ff0ab..32b775b6a 100644 --- a/spec/2021.12/API_specification/array_object.rst +++ b/spec/2021.12/API_specification/array_object.rst @@ -246,7 +246,7 @@ Bitwise Operators ------------------------------------------------- -.. currentmodule:: signatures.array_object +.. currentmodule:: array_api Attributes ---------- diff --git a/spec/2021.12/API_specification/constants.rst b/spec/2021.12/API_specification/constants.rst index 4d71ed380..abe256533 100644 --- a/spec/2021.12/API_specification/constants.rst +++ b/spec/2021.12/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.constants +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/creation_functions.rst b/spec/2021.12/API_specification/creation_functions.rst index c34f67378..9984ff04c 100644 --- a/spec/2021.12/API_specification/creation_functions.rst +++ b/spec/2021.12/API_specification/creation_functions.rst @@ -11,7 +11,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.creation_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/data_type_functions.rst b/spec/2021.12/API_specification/data_type_functions.rst index 4b35a297a..bb32d2b7f 100644 --- a/spec/2021.12/API_specification/data_type_functions.rst +++ b/spec/2021.12/API_specification/data_type_functions.rst @@ -9,7 +9,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.data_type_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst index f40006c4e..b2393c1a2 100644 --- a/spec/2021.12/API_specification/data_types.rst +++ b/spec/2021.12/API_specification/data_types.rst @@ -100,7 +100,7 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: signatures.data_types +.. currentmodule:: array_api .. autosummary:: :toctree: generated diff --git a/spec/2021.12/API_specification/elementwise_functions.rst b/spec/2021.12/API_specification/elementwise_functions.rst index 316ac8ce9..02e3d50b6 100644 --- a/spec/2021.12/API_specification/elementwise_functions.rst +++ b/spec/2021.12/API_specification/elementwise_functions.rst @@ -19,7 +19,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.elementwise_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/indexing.rst b/spec/2021.12/API_specification/indexing.rst index 13fe70a3f..6d5e77a5b 100644 --- a/spec/2021.12/API_specification/indexing.rst +++ b/spec/2021.12/API_specification/indexing.rst @@ -154,7 +154,7 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult - Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. .. note:: - Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. - Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. @@ -181,7 +181,7 @@ Boolean Array Indexing An array must support indexing where the **sole index** is an ``M``-dimensional boolean array ``B`` with shape ``S1 = (s1, ..., sM)`` according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S2 = (s1, ..., sM, ..., sN)``. .. note:: - The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~signatures.manipulation_functions.expand_dims`. + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~array_api.expand_dims`. - If ``N >= M``, then ``A[B]`` must replace the first ``M`` dimensions of ``A`` with a single dimension having a size equal to the number of ``True`` elements in ``B``. The values in the resulting array must be in row-major (C-style order); this is equivalent to ``A[nonzero(B)]``. diff --git a/spec/2021.12/API_specification/linear_algebra_functions.rst b/spec/2021.12/API_specification/linear_algebra_functions.rst index c12144aa4..9bae18e77 100644 --- a/spec/2021.12/API_specification/linear_algebra_functions.rst +++ b/spec/2021.12/API_specification/linear_algebra_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t * Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. * Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. -.. currentmodule:: signatures.linear_algebra_functions +.. currentmodule:: array_api Objects in API -------------- diff --git a/spec/2021.12/API_specification/manipulation_functions.rst b/spec/2021.12/API_specification/manipulation_functions.rst index f2fcbccc5..86ad2697f 100644 --- a/spec/2021.12/API_specification/manipulation_functions.rst +++ b/spec/2021.12/API_specification/manipulation_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.manipulation_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/searching_functions.rst b/spec/2021.12/API_specification/searching_functions.rst index b8a2b39a5..bf09e4c8a 100644 --- a/spec/2021.12/API_specification/searching_functions.rst +++ b/spec/2021.12/API_specification/searching_functions.rst @@ -16,7 +16,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.searching_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/set_functions.rst b/spec/2021.12/API_specification/set_functions.rst index 4ba2ad424..b7072d100 100644 --- a/spec/2021.12/API_specification/set_functions.rst +++ b/spec/2021.12/API_specification/set_functions.rst @@ -12,7 +12,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.set_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/sorting_functions.rst b/spec/2021.12/API_specification/sorting_functions.rst index da0ff99d1..19d7fb439 100644 --- a/spec/2021.12/API_specification/sorting_functions.rst +++ b/spec/2021.12/API_specification/sorting_functions.rst @@ -19,7 +19,7 @@ A conforming implementation of the array API standard must provide and support t While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. -.. currentmodule:: signatures.sorting_functions +.. currentmodule:: array_api Objects in API -------------- diff --git a/spec/2021.12/API_specification/statistical_functions.rst b/spec/2021.12/API_specification/statistical_functions.rst index d87f5d25a..6734506ed 100644 --- a/spec/2021.12/API_specification/statistical_functions.rst +++ b/spec/2021.12/API_specification/statistical_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.statistical_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/API_specification/utility_functions.rst b/spec/2021.12/API_specification/utility_functions.rst index 887819194..f869b4321 100644 --- a/spec/2021.12/API_specification/utility_functions.rst +++ b/spec/2021.12/API_specification/utility_functions.rst @@ -15,7 +15,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: signatures.utility_functions +.. currentmodule:: array_api .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index 33fccbca8..d9ec5b030 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -1,206 +1,7 @@ -# Configuration file for the Sphinx documentation builder. -# -# This file only contains a selection of the most common options. For a full -# list see the documentation: -# https://www.sphinx-doc.org/en/master/usage/configuration.html - -# -- Path setup -------------------------------------------------------------- - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# -import os import sys -import sphinx_material -sys.path.insert(0, os.path.abspath('./API_specification')) - -# -- Project information ----------------------------------------------------- - -project = 'Python array API standard' -copyright = '2020, Consortium for Python Data API Standards' -author = 'Consortium for Python Data API Standards' - -# The full version, including alpha/beta/rc tags -release = '2021.12' - - -# -- General configuration --------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. -extensions = [ - 'myst_parser', - 'sphinx.ext.extlinks', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx_markdown_tables', - 'sphinx_copybutton', - 'sphinx.ext.autosummary', - 'sphinx.ext.napoleon', - 'sphinx.ext.autodoc', -] - -autosummary_generate = True -autodoc_typehints = 'signature' -add_module_names = False -napoleon_custom_sections = [('Returns', 'params_style')] -default_role = 'code' - -# nitpicky = True makes Sphinx warn whenever a cross-reference target can't be -# found. -nitpicky = True -# autodoc wants to make cross-references for every type hint. But a lot of -# them don't actually refer to anything that we have a document for. -nitpick_ignore = [ - ('py:class', 'array'), - ('py:class', 'device'), - ('py:class', 'dtype'), - ('py:class', 'NestedSequence'), - ('py:class', 'SupportsBufferProtocol'), - ('py:class', 'collections.abc.Sequence'), - ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:class', "Union[int, float, Literal[inf, - inf]]"), - ('py:obj', "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:obj', "typing.Union[int, float, typing.Literal[inf, - inf]]"), - ('py:class', 'PyCapsule'), - ('py:class', 'enum.Enum'), - ('py:class', 'ellipsis'), - ('py:class', 'finfo_object'), - ('py:class', 'iinfo_object'), -] -# In array_object.py we have to use aliased names for some types because they -# would otherwise refer back to method objects of array -autodoc_type_aliases = { - 'array': 'array', - 'Device': 'device', - 'Dtype': 'dtype', -} - -# Make autosummary show the signatures of functions in the tables using actual -# Python syntax. There's currently no supported way to do this, so we have to -# just patch out the function that processes the signatures. See -# https://github.com/sphinx-doc/sphinx/issues/10053. -import sphinx.ext.autosummary as autosummary_mod -if hasattr(autosummary_mod, '_module'): - # It's a sphinx deprecated module wrapper object - autosummary_mod = autosummary_mod._module -autosummary_mod.mangle_signature = lambda sig, max_chars=30: sig - -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] - -# MyST options -myst_heading_anchors = 3 -myst_enable_extensions = ["colon_fence"] - -# -- Options for HTML output ------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# -extensions.append("sphinx_material") -html_theme_path = sphinx_material.html_theme_path() -html_context = sphinx_material.get_html_context() -html_theme = 'sphinx_material' - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] - - -# -- Material theme options (see theme.conf for more information) ------------ -html_show_sourcelink = False -html_sidebars = { - "**": ["logo-text.html", "globaltoc.html", "localtoc.html", "searchbox.html"] -} - -html_theme_options = { - - # Set the name of the project to appear in the navigation. - 'nav_title': f'Python array API standard {release}', - - # Set you GA account ID to enable tracking - #'google_analytics_account': 'UA-XXXXX', - - # Specify a base_url used to generate sitemap.xml. If not - # specified, then no sitemap will be built. - #'base_url': 'https://project.github.io/project', - - # Set the color and the accent color (see - # https://material.io/design/color/the-color-system.html) - 'color_primary': 'indigo', - 'color_accent': 'green', - - # Set the repo location to get a badge with stats - #'repo_url': 'https://github.com/project/project/', - #'repo_name': 'Project', - - "html_minify": False, - "html_prettify": False, - "css_minify": True, - "logo_icon": "", - "repo_type": "github", - "touch_icon": "images/apple-icon-152x152.png", - "theme_color": "#2196f3", - "master_doc": False, - - # Visible levels of the global TOC; -1 means unlimited - 'globaltoc_depth': 2, - # If False, expand all TOC entries - 'globaltoc_collapse': True, - # If True, show hidden TOC entries - 'globaltoc_includehidden': True, - - "nav_links": [ - {"href": "index", "internal": True, "title": "Array API standard"}, - { - "href": "https://data-apis.org", - "internal": False, - "title": "Consortium for Python Data API Standards", - }, - ], - "heroes": { - "index": "A common API for array and tensor Python libraries", - #"customization": "Configuration options to personalize your site.", - }, - - "version_dropdown": True, - "version_json": "../versions.json", - "table_classes": ["plain"], -} - - -todo_include_todos = True -#html_favicon = "images/favicon.ico" - -html_use_index = True -html_domain_indices = True - -extlinks = { - "duref": ( - "http://docutils.sourceforge.net/docs/ref/rst/" "restructuredtext.html#%s", - "", - ), - "durole": ("http://docutils.sourceforge.net/docs/ref/rst/" "roles.html#%s", ""), - "dudir": ("http://docutils.sourceforge.net/docs/ref/rst/" "directives.html#%s", ""), - "pypa": ("https://packaging.python.org/%s", ""), -} - -def process_signature(app, what, name, obj, options, signature, return_annotation): - if signature: - signature = signature.replace("signatures._types.", "") - if return_annotation: - return_annotation = return_annotation.replace("signatures._types.", "") - return signature, return_annotation +from array_api_stubs import _2021_12 as stubs_mod +from _array_api_conf import * -def setup(app): - app.connect("autodoc-process-signature", process_signature) +release = "2021.12" +sys.modules["array_api"] = stubs_mod diff --git a/spec/2021.12/extensions/linear_algebra_functions.rst b/spec/2021.12/extensions/linear_algebra_functions.rst index b82a913de..dbe643bed 100644 --- a/spec/2021.12/extensions/linear_algebra_functions.rst +++ b/spec/2021.12/extensions/linear_algebra_functions.rst @@ -74,7 +74,7 @@ Accordingly, the standardization process affords the opportunity to reduce inter where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. -.. currentmodule:: signatures.linalg +.. currentmodule:: array_api.linalg Objects in API -------------- diff --git a/spec/2022.12/API_specification/data_types.rst b/spec/2022.12/API_specification/data_types.rst index a9be88181..e9f6ff732 100644 --- a/spec/2022.12/API_specification/data_types.rst +++ b/spec/2022.12/API_specification/data_types.rst @@ -101,13 +101,13 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: array_api.data_types +.. currentmodule:: array_api .. autosummary:: :toctree: generated :template: method.rst - __eq__ + dtype.__eq__ .. _data-type-defaults: diff --git a/src/array_api_stubs/_2021_12/__init__.py b/src/array_api_stubs/_2021_12/__init__.py index e69de29bb..28584daf7 100644 --- a/src/array_api_stubs/_2021_12/__init__.py +++ b/src/array_api_stubs/_2021_12/__init__.py @@ -0,0 +1,22 @@ +"""Function stubs and API documentation for the array API standard.""" + +from .array_object import * +from .constants import * +from .creation_functions import * +from .data_type_functions import * +from . import data_types as dtype +from .elementwise_functions import * +from .linear_algebra_functions import * +from .manipulation_functions import * +from .searching_functions import * +from .set_functions import * +from .sorting_functions import * +from .statistical_functions import * +from .utility_functions import * +from . import linalg + + +__array_api_version__: str = "YYYY.MM" +""" +String representing the version of the array API specification which the conforming implementation adheres to. +""" diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index 970f641a1..ac6890f71 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -135,7 +135,7 @@ def __abs__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.abs`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -181,7 +181,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.add`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -202,7 +202,7 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_and`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: @@ -239,7 +239,7 @@ def __bool__(self: array, /) -> bool: def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: """ - Exports the array for consumption by :func:`~signatures.creation_functions.from_dlpack` as a DLPack capsule. + Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. Parameters ---------- @@ -294,7 +294,7 @@ def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> P def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: """ - Returns device type and device ID in DLPack format. Meant for use within :func:`~signatures.creation_functions.from_dlpack`. + Returns device type and device ID in DLPack format. Meant for use within :func:`~array_api.from_dlpack`. Parameters ---------- @@ -336,7 +336,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. """ def __float__(self: array, /) -> float: @@ -411,7 +411,7 @@ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.floor_divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. """ def __ge__(self: array, other: Union[int, float, array], /) -> array: @@ -432,7 +432,7 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. """ def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: @@ -470,7 +470,7 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.greater`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. """ def __index__(self: array, /) -> int: @@ -522,7 +522,7 @@ def __invert__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_invert`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_invert`. """ def __le__(self: array, other: Union[int, float, array], /) -> array: @@ -543,7 +543,7 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -564,7 +564,7 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_left_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: @@ -585,7 +585,7 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.less`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. """ def __matmul__(self: array, other: array, /) -> array: @@ -616,7 +616,7 @@ def __matmul__(self: array, other: array, /) -> array: .. note:: - Results must equal the results returned by the equivalent function :func:`~signatures.linear_algebra_functions.matmul`. + Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. **Raises** @@ -676,7 +676,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.remainder`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ def __mul__(self: array, other: Union[int, float, array], /) -> array: @@ -715,7 +715,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.multiply`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -736,7 +736,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.not_equal`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. """ def __neg__(self: array, /) -> array: @@ -758,7 +758,7 @@ def __neg__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.negative`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -779,7 +779,7 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_or`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -798,7 +798,7 @@ def __pos__(self: array, /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.positive`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: @@ -853,7 +853,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.pow`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -874,7 +874,7 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_right_shift`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: @@ -918,7 +918,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.subtract`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -971,7 +971,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.divide`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: @@ -992,7 +992,7 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~signatures.elementwise_functions.bitwise_xor`. + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index 88db02340..3285a386d 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -54,7 +54,7 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr .. admonition:: Note :class: note - If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`signatures.data_type_functions.astype`. + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`array_api.astype`. .. note:: If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 275fa3158..0749daf8e 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -157,7 +157,7 @@ def inv(x: array, /) -> array: def matmul(x1: array, x2: array, /) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.matmul`. + Alias for :func:`~array_api.matmul`. """ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: @@ -249,7 +249,7 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a def matrix_transpose(x: array, /) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.matrix_transpose`. + Alias for :func:`~array_api.matrix_transpose`. """ def outer(x1: array, x2: array, /) -> array: @@ -406,7 +406,7 @@ def svdvals(x: array, /) -> array: def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.tensordot`. + Alias for :func:`~array_api.tensordot`. """ def trace(x: array, /, *, offset: int = 0) -> array: @@ -440,7 +440,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ - Alias for :func:`~signatures.linear_algebra_functions.vecdot`. + Alias for :func:`~array_api.vecdot`. """ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: diff --git a/src/array_api_stubs/_2022_12/__init__.py b/src/array_api_stubs/_2022_12/__init__.py index 32f88750d..12b6d9fbb 100644 --- a/src/array_api_stubs/_2022_12/__init__.py +++ b/src/array_api_stubs/_2022_12/__init__.py @@ -4,7 +4,7 @@ from .constants import * from .creation_functions import * from .data_type_functions import * -import array_api.data_types as dtype +from . import data_types as dtype from .elementwise_functions import * from .indexing_functions import * from .linear_algebra_functions import * diff --git a/src/array_api_stubs/_draft/__init__.py b/src/array_api_stubs/_draft/__init__.py index 32f88750d..12b6d9fbb 100644 --- a/src/array_api_stubs/_draft/__init__.py +++ b/src/array_api_stubs/_draft/__init__.py @@ -4,7 +4,7 @@ from .constants import * from .creation_functions import * from .data_type_functions import * -import array_api.data_types as dtype +from . import data_types as dtype from .elementwise_functions import * from .indexing_functions import * from .linear_algebra_functions import * From 85df0ea8c931ca5a4f5bcda705ce00a01caa967e Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 14:07:29 +0000 Subject: [PATCH 364/551] Fix `2022.12` building --- spec/2022.12/conf.py | 7 +++++++ src/array_api_stubs/__init__.py | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 spec/2022.12/conf.py diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py new file mode 100644 index 000000000..e9d652d44 --- /dev/null +++ b/spec/2022.12/conf.py @@ -0,0 +1,7 @@ +import sys + +from array_api_stubs import _2022_12 as stubs_mod +from _array_api_conf import * + +release = "2022.12" +sys.modules["array_api"] = stubs_mod diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index 54614644a..b3c7f1976 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1,2 +1,2 @@ -from . import _2021_12, _draft +from . import _2021_12, _2022_12, _draft From a206273f3c9ad1e6bff1ef1db47c6b45b2c1894c Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Fri, 6 Jan 2023 14:09:42 +0000 Subject: [PATCH 365/551] Update all docs building --- Makefile | 3 ++- spec/_ghpages/versions.json | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 451b9224c..77a848598 100644 --- a/Makefile +++ b/Makefile @@ -18,5 +18,6 @@ build: -cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" -touch "$(BUILDDIR)/.nojekyll" -sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) - -cp -r "$(BUILDDIR)/2021.12" "$(BUILDDIR)/latest" + -sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) + -cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" -sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json index 5a6aa4692..ad38507bb 100644 --- a/spec/_ghpages/versions.json +++ b/spec/_ghpages/versions.json @@ -1,5 +1,6 @@ { "2021.12": "2021.12", + "2022.12": "2022.12", "latest": "latest", "draft": "draft" } From 58f2e59c91100ae55cb1d8f41124037e3e0e580e Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Sat, 7 Jan 2023 09:17:31 +0000 Subject: [PATCH 366/551] Fix image refs, restore old images --- spec/2021.12/API_specification/data_types.rst | 2 +- .../API_specification/type_promotion.rst | 2 +- spec/2021.12/assumptions.md | 2 +- spec/2021.12/purpose_and_scope.md | 2 +- .../API_specification/type_promotion.rst | 2 +- spec/2022.12/assumptions.md | 2 +- spec/2022.12/purpose_and_scope.md | 2 +- spec/_static/images/dtype_promotion_complex.png | Bin 0 -> 10433 bytes .../dtype_promotion_lattice_no_complex.png | Bin 0 -> 65646 bytes spec/draft/API_specification/type_promotion.rst | 2 +- spec/draft/assumptions.md | 2 +- spec/draft/purpose_and_scope.md | 2 +- 12 files changed, 10 insertions(+), 10 deletions(-) create mode 100644 spec/_static/images/dtype_promotion_complex.png create mode 100644 spec/_static/images/dtype_promotion_lattice_no_complex.png diff --git a/spec/2021.12/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst index b2393c1a2..49373a6f5 100644 --- a/spec/2021.12/API_specification/data_types.rst +++ b/spec/2021.12/API_specification/data_types.rst @@ -72,7 +72,7 @@ IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-20 ``complex64`` and ``complex128`` data types are expected to be included in the next version of this standard and to have the following casting rules (will be added to :ref:`type-promotion`): - .. image:: /_static/images/dtype_promotion_complex.png + .. image:: ../../_static/images/dtype_promotion_complex.png See `array-api/issues/102 `_ for more details diff --git a/spec/2021.12/API_specification/type_promotion.rst b/spec/2021.12/API_specification/type_promotion.rst index d30f6517c..2b1a422a0 100644 --- a/spec/2021.12/API_specification/type_promotion.rst +++ b/spec/2021.12/API_specification/type_promotion.rst @@ -7,7 +7,7 @@ Type Promotion Rules Type promotion rules can be understood at a high level from the following diagram: -.. image:: /_static/images/dtype_promotion_lattice.png +.. image:: ../../_static/images/dtype_promotion_lattice_no_complex.png :target: Type promotion diagram *Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* diff --git a/spec/2021.12/assumptions.md b/spec/2021.12/assumptions.md index 3a315e6cd..3a90710ea 100644 --- a/spec/2021.12/assumptions.md +++ b/spec/2021.12/assumptions.md @@ -35,7 +35,7 @@ such a coupling. Facilitation support of multiple array types in downstream libraries is an important use case however, the assumed dependency structure for that is: -![dependency assumptions diagram](_static/images/dependency_assumption_diagram.png) +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared diff --git a/spec/2021.12/purpose_and_scope.md b/spec/2021.12/purpose_and_scope.md index fc8433c7f..4678ba064 100644 --- a/spec/2021.12/purpose_and_scope.md +++ b/spec/2021.12/purpose_and_scope.md @@ -111,7 +111,7 @@ Furthermore, meta-topics included in this standard include: The concrete set of functionality that is in scope for this version of the standard is shown in this diagram: -![Scope of array API](_static/images/scope_of_array_API.png) +![Scope of array API](../_static/images/scope_of_array_API.png) **Goals** for the API standard include: diff --git a/spec/2022.12/API_specification/type_promotion.rst b/spec/2022.12/API_specification/type_promotion.rst index fc9f6e1bf..339b90e45 100644 --- a/spec/2022.12/API_specification/type_promotion.rst +++ b/spec/2022.12/API_specification/type_promotion.rst @@ -7,7 +7,7 @@ Type Promotion Rules Type promotion rules can be understood at a high level from the following diagram: -.. image:: /_static/images/dtype_promotion_lattice.png +.. image:: ../../_static/images/dtype_promotion_lattice.png :target: Type promotion diagram *Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* diff --git a/spec/2022.12/assumptions.md b/spec/2022.12/assumptions.md index 3a315e6cd..3a90710ea 100644 --- a/spec/2022.12/assumptions.md +++ b/spec/2022.12/assumptions.md @@ -35,7 +35,7 @@ such a coupling. Facilitation support of multiple array types in downstream libraries is an important use case however, the assumed dependency structure for that is: -![dependency assumptions diagram](_static/images/dependency_assumption_diagram.png) +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared diff --git a/spec/2022.12/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md index 62e9bb8ba..eee3c7f4c 100644 --- a/spec/2022.12/purpose_and_scope.md +++ b/spec/2022.12/purpose_and_scope.md @@ -111,7 +111,7 @@ Furthermore, meta-topics included in this standard include: The concrete set of functionality that is in scope for this version of the standard is shown in this diagram: -![Scope of array API](_static/images/scope_of_array_API.png) +![Scope of array API](../_static/images/scope_of_array_API.png) **Goals** for the API standard include: diff --git a/spec/_static/images/dtype_promotion_complex.png b/spec/_static/images/dtype_promotion_complex.png new file mode 100644 index 0000000000000000000000000000000000000000..3503b07f56a885d59a397d35ae3cfc164a4909ef GIT binary patch literal 10433 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 M3RNk(WBK?00t!l|VgLXD literal 0 HcmV?d00001 diff --git a/spec/_static/images/dtype_promotion_lattice_no_complex.png b/spec/_static/images/dtype_promotion_lattice_no_complex.png new file mode 100644 index 0000000000000000000000000000000000000000..669d3047683d4e149ee03f560bc33093d76977a1 GIT binary patch literal 65646 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 Date: Sat, 7 Jan 2023 09:20:52 +0000 Subject: [PATCH 367/551] Fix license page --- spec/{ => 2022.12}/license.rst | 2 +- spec/draft/license.rst | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) rename spec/{ => 2022.12}/license.rst (87%) create mode 100644 spec/draft/license.rst diff --git a/spec/license.rst b/spec/2022.12/license.rst similarity index 87% rename from spec/license.rst rename to spec/2022.12/license.rst index 8d4b6d1fd..06ec75dfc 100644 --- a/spec/license.rst +++ b/spec/2022.12/license.rst @@ -5,5 +5,5 @@ All content on this website and the corresponding `GitHub repository `__ is licensed under the following license: - .. include:: ../LICENSE + .. include:: ../../LICENSE :parser: myst_parser.sphinx_ diff --git a/spec/draft/license.rst b/spec/draft/license.rst new file mode 100644 index 000000000..06ec75dfc --- /dev/null +++ b/spec/draft/license.rst @@ -0,0 +1,9 @@ +License +======= + +All content on this website and the corresponding +`GitHub repository `__ is licensed +under the following license: + + .. include:: ../../LICENSE + :parser: myst_parser.sphinx_ From f06c5a0b1ad723cd8e1197f990769c2762269ead Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Sat, 7 Jan 2023 09:26:03 +0000 Subject: [PATCH 368/551] Update changelog refs --- spec/2022.12/changelog.rst | 2 +- spec/draft/changelog.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/2022.12/changelog.rst b/spec/2022.12/changelog.rst index e0993307d..701a3dbcd 100644 --- a/spec/2022.12/changelog.rst +++ b/spec/2022.12/changelog.rst @@ -1,5 +1,5 @@ Changelog per API standard version ================================== -.. include:: ../CHANGELOG.md +.. include:: ../../CHANGELOG.md :parser: myst_parser.sphinx_ diff --git a/spec/draft/changelog.rst b/spec/draft/changelog.rst index e0993307d..701a3dbcd 100644 --- a/spec/draft/changelog.rst +++ b/spec/draft/changelog.rst @@ -1,5 +1,5 @@ Changelog per API standard version ================================== -.. include:: ../CHANGELOG.md +.. include:: ../../CHANGELOG.md :parser: myst_parser.sphinx_ From 6eb8df3926370ae1368b262bb98b6c0932d854ad Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Sat, 7 Jan 2023 13:03:49 +0000 Subject: [PATCH 369/551] Standardise `dtype.__eq__` autodocs accross versions --- spec/2021.12/API_specification/data_types.rst | 2 +- spec/2022.12/API_specification/data_types.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/2021.12/API_specification/data_types.rst b/spec/2021.12/API_specification/data_types.rst index 49373a6f5..48a8bd1a0 100644 --- a/spec/2021.12/API_specification/data_types.rst +++ b/spec/2021.12/API_specification/data_types.rst @@ -100,7 +100,7 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: array_api +.. currentmodule:: array_api.data_types .. autosummary:: :toctree: generated diff --git a/spec/2022.12/API_specification/data_types.rst b/spec/2022.12/API_specification/data_types.rst index e9f6ff732..a9be88181 100644 --- a/spec/2022.12/API_specification/data_types.rst +++ b/spec/2022.12/API_specification/data_types.rst @@ -101,13 +101,13 @@ Methods .. NOTE: please keep the functions in alphabetical order -.. currentmodule:: array_api +.. currentmodule:: array_api.data_types .. autosummary:: :toctree: generated :template: method.rst - dtype.__eq__ + __eq__ .. _data-type-defaults: From 96a38c30c64cbcdb39e78d9f7162ebbcf4c46d22 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 18 Jan 2023 09:49:11 +0000 Subject: [PATCH 370/551] Minor grammar fixes Co-authored-by: Athan --- PACKAGE.md | 4 ++-- README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/PACKAGE.md b/PACKAGE.md index 199c4e2a2..dc5079d2a 100644 --- a/PACKAGE.md +++ b/PACKAGE.md @@ -1,7 +1,7 @@ # Stubs for the array API standard -Documentation specific to singular Python objects in the spec (i.e. functions, -methods and attributes) are infact represented by stub objects in the package +Documentation specific to singular Python objects in the spec (i.e., functions, +methods and attributes) are in fact represented by stub objects in the package `array-api-stubs`. These stubs ultimately get rendered via the autodoc capabilities in Sphinx. diff --git a/README.md b/README.md index 96edb338e..529afdbb9 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ this array API standard. ## Building docs locally -The spec website comprises of multiple Sphinx docs (one for each spec version), +The spec website is comprised of multiple Sphinx docs (one for each spec version), all of which exist in `spec/` and rely on the modules found in `src/` (most notably `array_api_stubs`). To install these modules and the additional dependencies of the Sphinx docs, you can use @@ -35,7 +35,7 @@ $ sphinx-build spec/draft/ _site/draft/ ``` To build the whole website, which includes every version of -the spec, you can utilize the `make` commands defined in `spec/Makefile`, e.g. +the spec, you can utilize the `make` commands defined in `spec/Makefile`; e.g., ```sh $ make From 399cd772d86a404e8902533dff507d110743ebe9 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Wed, 18 Jan 2023 09:50:56 +0000 Subject: [PATCH 371/551] Update copyright date (after accidentally reverting it) --- src/_array_api_conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 161590fea..ca8d2aaed 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- project = 'Python array API standard' -copyright = '2020, Consortium for Python Data API Standards' +copyright = '2020-2022, Consortium for Python Data API Standards' author = 'Consortium for Python Data API Standards' # -- General configuration --------------------------------------------------- From 8d48911ce0c68c3952d84580c2b1760801285930 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Wed, 1 Feb 2023 08:45:40 +0000 Subject: [PATCH 372/551] CI: ensure make propagates errors and CircleCI fails on doc build failure This got broken in a recent change to the Makefile --- Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 77a848598..a48139ddc 100644 --- a/Makefile +++ b/Makefile @@ -12,12 +12,12 @@ clean: -find . -type d -name generated -exec rm -rf {} + build: - -mkdir -p $(BUILDDIR) - -cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" - -cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" - -cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" - -touch "$(BUILDDIR)/.nojekyll" - -sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) - -sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) - -cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" - -sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) + mkdir -p $(BUILDDIR) + cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" + cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" + cp "$(SOURCEDIR)/_ghpages/index.html" "$(BUILDDIR)/index.html" + touch "$(BUILDDIR)/.nojekyll" + sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) + sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) + cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" + sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) From 3d918783ac7f11cb5b31681b2badddeca81dc71e Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Wed, 1 Feb 2023 04:53:03 -0500 Subject: [PATCH 373/551] Add admonitions for new and changed APIs in 2022 version (#585) - Add version changed to functions that were modified for complex support in 2022 - Add version added to functions created in 2022 Co-authored-by: Ralf Gommers --- src/array_api_stubs/_draft/array_object.py | 67 +++++++++ .../_draft/creation_functions.py | 47 +++++++ .../_draft/data_type_functions.py | 21 +++ .../_draft/elementwise_functions.py | 129 ++++++++++++++++++ src/array_api_stubs/_draft/fft.py | 70 ++++++++++ .../_draft/indexing_functions.py | 5 + src/array_api_stubs/_draft/linalg.py | 107 ++++++++++++++- .../_draft/linear_algebra_functions.py | 18 ++- .../_draft/searching_functions.py | 6 + src/array_api_stubs/_draft/set_functions.py | 24 ++++ .../_draft/statistical_functions.py | 6 + .../_draft/utility_functions.py | 12 ++ 12 files changed, 510 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 89e5ee1c3..cf6adcf3c 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -136,9 +136,14 @@ def __abs__(self: array, /) -> array: out: array an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -157,9 +162,14 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -228,6 +238,9 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __complex__(self: array, /) -> complex: @@ -260,6 +273,8 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. - If ``self`` is a finite number, the result is ``self + 0j``. + + .. versionadded:: 2022.12 """ def __dlpack__( @@ -326,6 +341,11 @@ def __dlpack__( errors are raised when export fails for other reasons (e.g., incorrect arguments passed or out of memory). + Notes + ----- + + .. versionchanged:: 2022.12 + Added BufferError. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -401,6 +421,9 @@ def __float__(self: array, /) -> float: - If ``self`` is ``True``, the result is ``1``. - If ``self`` is ``False``, the result is ``0``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: @@ -551,6 +574,9 @@ def __int__(self: array, /) -> int: - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. - If ``self`` is ``NaN``, raise ``ValueError``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __invert__(self: array, /) -> array: @@ -671,6 +697,8 @@ def __matmul__(self: array, other: array, /) -> array: - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. - The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. @@ -682,6 +710,9 @@ def __matmul__(self: array, other: array, /) -> array: - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __mod__(self: array, other: Union[int, float, array], /) -> array: @@ -727,9 +758,14 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -749,8 +785,14 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + Notes + ----- + .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __neg__(self: array, /) -> array: @@ -773,9 +815,14 @@ def __neg__(self: array, /) -> array: out: array an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -813,9 +860,14 @@ def __pos__(self: array, /) -> array: out: array an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __pow__(self: array, other: Union[int, float, array], /) -> array: @@ -839,9 +891,14 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -913,9 +970,14 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -939,9 +1001,14 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 3f577b542..8736efc29 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -97,6 +97,12 @@ def asarray( ------- out: array an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -179,6 +185,12 @@ def eye( ------- out: array an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -237,6 +249,12 @@ def full( ------- out: array an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -273,6 +291,12 @@ def full_like( ------- out: array an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -334,12 +358,17 @@ def linspace( out: array a one-dimensional array containing evenly spaced values. + Notes + ----- .. note:: While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. .. note:: As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -367,6 +396,12 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -395,6 +430,12 @@ def ones( ------- out: array an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -420,6 +461,12 @@ def ones_like( ------- out: array an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 0f557852b..571871f6d 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -36,6 +36,12 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: ------- out: array an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -97,6 +103,14 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: - **dtype**: dtype real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -129,6 +143,8 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: - **dtype**: dtype integer data type. + + .. versionadded:: 2022.12 """ @@ -167,6 +183,11 @@ def isdtype( ------- out: bool boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 6b2a46e24..74ef7e98d 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -52,6 +52,9 @@ def abs(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -118,6 +121,9 @@ def acos(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -189,6 +195,9 @@ def acosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -254,6 +263,9 @@ def add(x1: array, x2: array, /) -> array: - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -308,6 +320,9 @@ def asin(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -370,6 +385,9 @@ def asinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -419,6 +437,9 @@ def atan(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -541,6 +562,9 @@ def atanh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -709,6 +733,11 @@ def conj(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -753,6 +782,9 @@ def cos(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -813,6 +845,9 @@ def cosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -893,6 +928,9 @@ def divide(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -934,6 +972,9 @@ def equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -987,6 +1028,9 @@ def exp(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1043,6 +1087,9 @@ def expm1(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1192,6 +1239,11 @@ def imag(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -1226,6 +1278,9 @@ def isfinite(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1258,6 +1313,9 @@ def isinf(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1289,6 +1347,9 @@ def isnan(x: array, /) -> array: - If ``a`` or ``b`` is ``NaN``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1390,6 +1451,9 @@ def log(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1449,6 +1513,9 @@ def log1p(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1488,6 +1555,9 @@ def log2(x: array, /) -> array: \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1527,6 +1597,9 @@ def log10(x: array, /) -> array: \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1703,6 +1776,9 @@ def multiply(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1725,6 +1801,12 @@ def negative(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1764,6 +1846,9 @@ def not_equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1780,6 +1865,12 @@ def positive(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1847,6 +1938,9 @@ def pow(x1: array, x2: array, /) -> array: .. note:: Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1863,6 +1957,11 @@ def real(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -1958,6 +2057,9 @@ def round(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2002,6 +2104,9 @@ def sign(x: array, /) -> array: - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2045,6 +2150,9 @@ def sin(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2105,6 +2213,9 @@ def sinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2133,6 +2244,9 @@ def square(x: array, /) -> array: **Special cases** For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2189,6 +2303,9 @@ def sqrt(x: array, /) -> array: - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2209,6 +2326,12 @@ def subtract(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2252,6 +2375,9 @@ def tan(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2316,6 +2442,9 @@ def tanh(x: array, /) -> array: For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 2eb428b0c..7979095fe 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -44,6 +44,11 @@ def fft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -90,6 +95,11 @@ def ifft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -143,6 +153,11 @@ def fftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -196,6 +211,11 @@ def ifftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -242,6 +262,11 @@ def rfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -288,6 +313,11 @@ def irfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -341,6 +371,11 @@ def rfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -394,6 +429,11 @@ def irfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -437,6 +477,11 @@ def hfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -480,6 +525,11 @@ def ihfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -507,6 +557,11 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar ------- out: array an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -536,6 +591,11 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a ------- out: array an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -559,6 +619,11 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -580,6 +645,11 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index e76ce7484..d57dc91e5 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -23,6 +23,11 @@ def take(x: array, indices: array, /, *, axis: int) -> array: ------- out: array 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``. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index b040251dd..20d1d54ff 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -38,6 +38,12 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: ------- out: array an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -66,9 +72,17 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. + **Raises** - - if provided an invalid ``axis``. - if the size of the axis over which to compute the cross product is not equal to ``3``. - if the size of the axis over which to compute the cross product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ @@ -87,6 +101,12 @@ def det(x: array, /) -> array: ------- out: array if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -154,9 +174,14 @@ def eigh(x: array, /) -> Tuple[array]: - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -192,9 +217,14 @@ def eigvalsh(x: array, /) -> array: out: array an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -224,6 +254,12 @@ def inv(x: array, /) -> array: ------- out: array an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -288,6 +324,12 @@ def matrix_norm( ------- out: array an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -306,6 +348,12 @@ def matrix_power(x: array, n: int, /) -> array: ------- out: array if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -326,6 +374,12 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a ------- out: array an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -348,6 +402,12 @@ def outer(x1: array, x2: array, /) -> array: ------- out: array a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -382,6 +442,12 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: ------- out: array an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -441,6 +507,12 @@ def qr( - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -490,6 +562,12 @@ def slogdet(x: array, /) -> Tuple[array, array]: - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -522,6 +600,12 @@ def solve(x1: array, x2: array, /) -> array: ------- out: array an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -571,6 +655,12 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -589,6 +679,12 @@ def svdvals(x: array, /) -> array: ------- out: array an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -653,6 +749,9 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -716,6 +815,12 @@ def vector_norm( ------- out: array an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index c8b6e50f8..9d949c067 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -32,6 +32,11 @@ def matmul(x1: array, x2: array, /) -> array: The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** @@ -40,6 +45,7 @@ def matmul(x1: array, x2: array, /) -> array: - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + """ @@ -101,6 +107,12 @@ def tensordot( ------- out: array an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -133,10 +145,14 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: out: array if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** - - if provided an invalid ``axis``. - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 9393ba71e..9dcc0f95c 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -75,6 +75,12 @@ def nonzero(x: array, /) -> Tuple[array, ...]: ------- out: Typle[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index dc95f58e8..661d3df90 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -38,6 +38,12 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -74,6 +80,12 @@ def unique_counts(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -110,6 +122,12 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -141,6 +159,12 @@ def unique_values(x: array, /) -> array: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 787faeeb9..93faaf31e 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -171,6 +171,9 @@ def prod( - If ``N`` is ``0``, the product is `1` (i.e., the empty product). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -265,6 +268,9 @@ def sum( - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index e70fe8aa6..64e5de297 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -33,6 +33,12 @@ def all( ------- out: array if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -68,6 +74,12 @@ def any( ------- out: array if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ From d8720324d5669099cfa24323b43f833274853a53 Mon Sep 17 00:00:00 2001 From: Matthew Barber Date: Tue, 28 Feb 2023 12:34:02 +0000 Subject: [PATCH 374/551] Improvments to doc building with `make` (#587) --- .circleci/config.yml | 4 ++-- .github/workflows/pages.yml | 4 ++-- Makefile | 14 +++++++++----- README.md | 34 +++++++++++++++++++++++----------- doc-requirements.txt | 7 +++++++ pyproject.toml | 11 ----------- spec/2021.12/conf.py | 2 ++ spec/2022.12/conf.py | 2 ++ spec/draft/conf.py | 2 ++ 9 files changed, 49 insertions(+), 31 deletions(-) create mode 100644 doc-requirements.txt diff --git a/.circleci/config.yml b/.circleci/config.yml index cecae43c8..b35ab8506 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,8 +19,8 @@ jobs: name: build docs no_output_timeout: 25m command: | - pip install .[doc] - make + pip install -r doc-requirements.txt + make spec - store_artifacts: path: _site/ diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index e615135d3..b328abc11 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -76,14 +76,14 @@ jobs: # Install dependencies: - name: 'Install dependencies' run: | - pip install .[doc] + pip install -r doc-requirements.txt # Generate the documentation: - name: 'Build documentation' run: | # Turn warnings into errors and ensure .doctrees is not deployed: export SPHINXOPTS="-b html -WT --keep-going -d doctrees" - make + make spec # Configure Git: - name: 'Configure Git' diff --git a/Makefile b/Makefile index a48139ddc..d23e05218 100644 --- a/Makefile +++ b/Makefile @@ -3,15 +3,19 @@ SPHINXOPTS ?= -W --keep-going SOURCEDIR = spec BUILDDIR = _site -.PHONY: default clean build +.PHONY: default clean draft spec -default: clean build +default: clean spec clean: - -rm -rf $(BUILDDIR) - -find . -type d -name generated -exec rm -rf {} + + rm -rf $(BUILDDIR) + find . -type d -name generated -exec rm -rf {} + -build: +draft: + mkdir -p $(BUILDDIR) + sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) + +spec: mkdir -p $(BUILDDIR) cp "$(SOURCEDIR)/_ghpages/_gitignore.txt" "$(BUILDDIR)/.gitignore" cp "$(SOURCEDIR)/_ghpages/versions.json" "$(BUILDDIR)/versions.json" diff --git a/README.md b/README.md index 529afdbb9..6c32aec19 100644 --- a/README.md +++ b/README.md @@ -18,31 +18,43 @@ this array API standard. ## Building docs locally -The spec website is comprised of multiple Sphinx docs (one for each spec version), -all of which exist in `spec/` and rely on the modules found in `src/` (most -notably `array_api_stubs`). To install these modules and the additional -dependencies of the Sphinx docs, you can use +### Quickstart + +To install the local stubs and additional dependencies of the Sphinx docs, you +can use `pip install -r doc-requirements.txt`. Then just running `make` at the +root of the repository should build the whole spec website. ```sh -$ pip install -e .[doc] # ensure you install the dependencies extra "doc" +$ pip install -r doc-requirements.txt +$ make +$ ls _site/ +2021.12/ draft/ index.html latest/ versions.json ``` +### The nitty-gritty + +The spec website is comprised of multiple Sphinx docs (one for each spec version), +all of which exist in `spec/` and rely on the modules found in `src/` (most +notably `array_api_stubs`). For purposes of building the docs, these `src/` +modules do not need to be installed as they are added to the `sys.path` at +runtime. + To build specific versions of the spec, run `sphinx-build` on the respective folder in `spec/`, e.g. ```sh -$ sphinx-build spec/draft/ _site/draft/ +$ sphinx-build spec/2012.12/ _site/2012.12/ ``` -To build the whole website, which includes every version of -the spec, you can utilize the `make` commands defined in `spec/Makefile`; e.g., +Additionally, `make draft` aliases ```sh -$ make -$ ls _site/ -2021.12/ draft/ index.html latest/ versions.json +$ sphinx-build spec/draft/ _site/draft/ ``` +To build the whole website, which includes every version of the spec, you can +utilize `make spec`. + ## Making a spec release diff --git a/doc-requirements.txt b/doc-requirements.txt new file mode 100644 index 000000000..230413784 --- /dev/null +++ b/doc-requirements.txt @@ -0,0 +1,7 @@ +sphinx==4.3.0 +sphinx-material==0.0.30 +myst-parser +sphinx_markdown_tables +sphinx_copybutton +docutils<0.18 +sphinx-math-dollar diff --git a/pyproject.toml b/pyproject.toml index b8240a665..f39bf48b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,17 +14,6 @@ Source = "https://github.com/data-apis/array-api/" Documentation = "https://data-apis.org/array-api/" Homepage = "https://data-apis.org/" -[project.optional-dependencies] -doc = [ - "sphinx==4.3.0", - "sphinx-material==0.0.30", - "myst-parser", - "sphinx_markdown_tables", - "sphinx_copybutton", - "docutils<0.18", - "sphinx-math-dollar", -] - [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index d9ec5b030..04af8974d 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -1,4 +1,6 @@ import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2021_12 as stubs_mod from _array_api_conf import * diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py index e9d652d44..fd05b644e 100644 --- a/spec/2022.12/conf.py +++ b/spec/2022.12/conf.py @@ -1,4 +1,6 @@ import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2022_12 as stubs_mod from _array_api_conf import * diff --git a/spec/draft/conf.py b/spec/draft/conf.py index f3804e7ad..4a57229b2 100644 --- a/spec/draft/conf.py +++ b/spec/draft/conf.py @@ -1,4 +1,6 @@ import sys +from pathlib import Path +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _draft as stubs_mod from _array_api_conf import * From 3612edc171bb5838c9c7d8b68c5325ad0b6c70aa Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Wed, 8 Mar 2023 15:46:46 -0500 Subject: [PATCH 375/551] Add imag to elementwise functions table of contents (#603) --- spec/2022.12/API_specification/elementwise_functions.rst | 1 + spec/draft/API_specification/elementwise_functions.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/spec/2022.12/API_specification/elementwise_functions.rst b/spec/2022.12/API_specification/elementwise_functions.rst index bc21e14b9..0e5fd0609 100644 --- a/spec/2022.12/API_specification/elementwise_functions.rst +++ b/spec/2022.12/API_specification/elementwise_functions.rst @@ -44,6 +44,7 @@ Objects in API floor_divide greater greater_equal + imag isfinite isinf isnan diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index bc21e14b9..0e5fd0609 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -44,6 +44,7 @@ Objects in API floor_divide greater greater_equal + imag isfinite isinf isnan From 94a24c8aa87f5cdfc9aa94ef845e63992d6bb018 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 14 Mar 2023 05:45:56 -0600 Subject: [PATCH 376/551] Make it clearer that the dtype kinds in isdtype are the string inputs (#610) --- .../_2022_12/data_type_functions.py | 14 +++++++------- src/array_api_stubs/_draft/data_type_functions.py | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/array_api_stubs/_2022_12/data_type_functions.py b/src/array_api_stubs/_2022_12/data_type_functions.py index 0f557852b..f3561b76f 100644 --- a/src/array_api_stubs/_2022_12/data_type_functions.py +++ b/src/array_api_stubs/_2022_12/data_type_functions.py @@ -148,13 +148,13 @@ def isdtype( - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: - - **bool**: boolean data types (e.g., ``bool``). - - **signed integer**: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). - - **unsigned integer**: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). - - **integral**: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. - - **real floating**: real-valued floating-point data types (e.g., ``float32``, ``float64``). - - **complex floating**: complex floating-point data types (e.g., ``complex64``, ``complex128``). - - **numeric**: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 571871f6d..700bffd90 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -164,13 +164,13 @@ def isdtype( - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: - - **bool**: boolean data types (e.g., ``bool``). - - **signed integer**: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). - - **unsigned integer**: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). - - **integral**: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. - - **real floating**: real-valued floating-point data types (e.g., ``float32``, ``float64``). - - **complex floating**: complex floating-point data types (e.g., ``complex64``, ``complex128``). - - **numeric**: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. From dc5e56d28521146f977f910cec3718dfd614de57 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 21 Mar 2023 18:20:29 +0000 Subject: [PATCH 377/551] Add a page on exceptions, and treat exceptions more consistently Closes gh-606 --- spec/draft/design_topics/exceptions.rst | 28 +++++++++++++++++++ spec/draft/design_topics/index.rst | 1 + .../_draft/manipulation_functions.py | 23 +++++++++++++-- 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 spec/draft/design_topics/exceptions.rst diff --git a/spec/draft/design_topics/exceptions.rst b/spec/draft/design_topics/exceptions.rst new file mode 100644 index 000000000..0a176c302 --- /dev/null +++ b/spec/draft/design_topics/exceptions.rst @@ -0,0 +1,28 @@ +.. _exceptions: + +Exceptions +========== + +This standard specifies expected syntax and semantics for a set of APIs. When +inputs to an API do not match what is expected, libraries may emit warnings, +raise exceptions, or misbehave in unexpected ways. In general it is not +possible to foresee or specify all the ways in which unexpected or invalid +inputs are provided. Therefore, this standard does not attempt to specify +exception or warning types to the extent needed in order to do exception +handling in a portable manner. In general, it is expected that array library +implementers follow `the guidance given by the documentation of the Python +language `__, and use either +fitting builtin exception or warning types that are appropriate for the +situation, or custom exceptions or warnings that derive from those builtin +ones. + +In specific cases, it may be useful to provide guidance to array library +authors regarding what an appropriate exception is. That guidance will be +phrased as *should* rather than *must* (typically in a *Raises* section), +because (a) there may be reasons for an implementer to deviate, and (b) more +often than not existing array library implementation already differ in their +choices and it may not be worth them breaking backwards compatibility in order +to comply with a "must" in this standard. + +In other cases, this standard will only specify that an exception should or +must be raised, but not mention what type of exception that is. diff --git a/spec/draft/design_topics/index.rst b/spec/draft/design_topics/index.rst index c8c5a0733..fa26359a7 100644 --- a/spec/draft/design_topics/index.rst +++ b/spec/draft/design_topics/index.rst @@ -11,6 +11,7 @@ Design topics & constraints device_support static_typing accuracy + exceptions complex_numbers C_API parallelism diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2d7179a8b..2a4b612f5 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -67,12 +67,17 @@ def expand_dims(x: array, /, *, axis: int = 0) -> array: x: array input array. axis: int - axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). An ``IndexError`` exception must be raised if provided an invalid ``axis`` position. + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). Returns ------- out: array an expanded output array having the same data type as ``x``. + + Raises + ------ + IndexError + If provided an invalid ``axis`` position, an ``IndexError`` should be raised. """ @@ -125,12 +130,18 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - boolean indicating whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying if possible, and may copy otherwise. Default: ``None``. Returns ------- out: array an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If ``copy=False`` and a copy would be necessary, a ``ValueError`` + should be raised. """ @@ -169,12 +180,18 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: x: array input array. axis: Union[int, Tuple[int, ...]] - axis (or axes) to squeeze. If a specified axis has a size greater than one, a ``ValueError`` must be raised. + axis (or axes) to squeeze. Returns ------- out: array an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If a specified axis has a size greater than one, i.e. it is not a + singleton dimension, a ``ValueError`` should be raised. """ From 371a4ed33d89bb23e5595d80b056d92d44257e4c Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 21 Mar 2023 13:47:23 -0500 Subject: [PATCH 378/551] Add favicon (#612) Co-authored-by: Ralf Gommers --- doc-requirements.txt | 1 + pyproject.toml | 12 ++++++++++++ spec/_static/images/favicon.png | Bin 0 -> 5152 bytes src/_array_api_conf.py | 14 +++++++++++--- 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 spec/_static/images/favicon.png diff --git a/doc-requirements.txt b/doc-requirements.txt index 230413784..488aa3e81 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -3,5 +3,6 @@ sphinx-material==0.0.30 myst-parser sphinx_markdown_tables sphinx_copybutton +sphinx_favicon docutils<0.18 sphinx-math-dollar diff --git a/pyproject.toml b/pyproject.toml index f39bf48b9..b4f991c45 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,6 +14,18 @@ Source = "https://github.com/data-apis/array-api/" Documentation = "https://data-apis.org/array-api/" Homepage = "https://data-apis.org/" +[project.optional-dependencies] +doc = [ + "sphinx==4.3.0", + "sphinx-material==0.0.30", + "myst-parser", + "sphinx_markdown_tables", + "sphinx_copybutton", + "docutils<0.18", + "sphinx-math-dollar", + "sphinx-favicon", +] + [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" diff --git a/spec/_static/images/favicon.png b/spec/_static/images/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..49b7d9d6fa9e82e24c907c324f53df2dbf11a222 GIT binary patch literal 5152 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 literal 0 HcmV?d00001 diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index ca8d2aaed..490d3a2aa 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -30,11 +30,12 @@ 'sphinx.ext.extlinks', 'sphinx.ext.intersphinx', 'sphinx.ext.todo', - 'sphinx_markdown_tables', - 'sphinx_copybutton', 'sphinx.ext.autosummary', 'sphinx.ext.napoleon', 'sphinx.ext.autodoc', + 'sphinx_copybutton', + 'sphinx_favicon', + 'sphinx_markdown_tables', ] autosummary_generate = True @@ -176,7 +177,14 @@ todo_include_todos = True -#html_favicon = "images/favicon.ico" + +favicons = [ + { + "rel": "icon", + "sizes": "196x195", + "href": "images/favicon.png", + }, +] html_use_index = True html_domain_indices = True From 8a3e6bc6bcd0dde6a22a7127ac83bc6691250707 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 21 Mar 2023 13:49:07 -0500 Subject: [PATCH 379/551] Add `unstack` (#604) --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index 4f43f0835..fc0e752b9 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -28,3 +28,4 @@ Objects in API roll squeeze stack + unstack diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2d7179a8b..28ffbcff2 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -199,6 +199,24 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ +def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: + """ + Splits an array in a sequence of arrays along the given axis. + + Parameters + ---------- + x: array + input array. + axis: int + axis along which the array will be split. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: Tuple[array, ...] + tuple of slices along the given dimension. All the arrays have the same shape. + """ + + __all__ = [ "broadcast_arrays", "broadcast_to", @@ -210,4 +228,5 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> "roll", "squeeze", "stack", + "unstack", ] From d89e7a7b9739353afcf49951686f804fa372e3fe Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 27 Mar 2023 13:07:16 -0500 Subject: [PATCH 380/551] Backport versionadded and versionchanged annotations to 2022.12 spec --- src/array_api_stubs/_2022_12/array_object.py | 66 ++++++++++ .../_2022_12/creation_functions.py | 47 +++++++ .../_2022_12/data_type_functions.py | 21 +++ .../_2022_12/elementwise_functions.py | 122 ++++++++++++++++++ src/array_api_stubs/_2022_12/fft.py | 70 ++++++++++ src/array_api_stubs/_2022_12/linalg.py | 105 +++++++++++++++ .../_2022_12/linear_algebra_functions.py | 16 +++ .../_2022_12/searching_functions.py | 6 + src/array_api_stubs/_2022_12/set_functions.py | 24 ++++ .../_2022_12/statistical_functions.py | 6 + .../_2022_12/utility_functions.py | 12 ++ 11 files changed, 495 insertions(+) diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index 89e5ee1c3..6cac6033d 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -136,9 +136,14 @@ def __abs__(self: array, /) -> array: out: array an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __add__(self: array, other: Union[int, float, array], /) -> array: @@ -157,9 +162,14 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __and__(self: array, other: Union[int, bool, array], /) -> array: @@ -228,6 +238,9 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __complex__(self: array, /) -> complex: @@ -260,6 +273,8 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. - If ``self`` is a finite number, the result is ``self + 0j``. + + .. versionadded:: 2022.12 """ def __dlpack__( @@ -326,6 +341,11 @@ def __dlpack__( errors are raised when export fails for other reasons (e.g., incorrect arguments passed or out of memory). + Notes + ----- + + .. versionchanged:: 2022.12 + Added BufferError. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -401,6 +421,9 @@ def __float__(self: array, /) -> float: - If ``self`` is ``True``, the result is ``1``. - If ``self`` is ``False``, the result is ``0``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: @@ -551,6 +574,9 @@ def __int__(self: array, /) -> int: - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. - If ``self`` is ``NaN``, raise ``ValueError``. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. """ def __invert__(self: array, /) -> array: @@ -671,6 +697,8 @@ def __matmul__(self: array, other: array, /) -> array: - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. - The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. @@ -682,6 +710,9 @@ def __matmul__(self: array, other: array, /) -> array: - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __mod__(self: array, other: Union[int, float, array], /) -> array: @@ -727,9 +758,14 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: @@ -748,9 +784,14 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __neg__(self: array, /) -> array: @@ -773,9 +814,14 @@ def __neg__(self: array, /) -> array: out: array an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __or__(self: array, other: Union[int, bool, array], /) -> array: @@ -794,9 +840,14 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __pos__(self: array, /) -> array: @@ -839,9 +890,14 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __rshift__(self: array, other: Union[int, array], /) -> array: @@ -913,9 +969,14 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __truediv__(self: array, other: Union[int, float, array], /) -> array: @@ -939,9 +1000,14 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + Notes + ----- .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __xor__(self: array, other: Union[int, bool, array], /) -> array: diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py index 3f577b542..8736efc29 100644 --- a/src/array_api_stubs/_2022_12/creation_functions.py +++ b/src/array_api_stubs/_2022_12/creation_functions.py @@ -97,6 +97,12 @@ def asarray( ------- out: array an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -179,6 +185,12 @@ def eye( ------- out: array an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -237,6 +249,12 @@ def full( ------- out: array an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -273,6 +291,12 @@ def full_like( ------- out: array an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -334,12 +358,17 @@ def linspace( out: array a one-dimensional array containing evenly spaced values. + Notes + ----- .. note:: While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. .. note:: As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -367,6 +396,12 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -395,6 +430,12 @@ def ones( ------- out: array an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -420,6 +461,12 @@ def ones_like( ------- out: array an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/data_type_functions.py b/src/array_api_stubs/_2022_12/data_type_functions.py index f3561b76f..700bffd90 100644 --- a/src/array_api_stubs/_2022_12/data_type_functions.py +++ b/src/array_api_stubs/_2022_12/data_type_functions.py @@ -36,6 +36,12 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: ------- out: array an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -97,6 +103,14 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: - **dtype**: dtype real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -129,6 +143,8 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: - **dtype**: dtype integer data type. + + .. versionadded:: 2022.12 """ @@ -167,6 +183,11 @@ def isdtype( ------- out: bool boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index 6b2a46e24..b502e091b 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -52,6 +52,9 @@ def abs(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -118,6 +121,9 @@ def acos(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -189,6 +195,9 @@ def acosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -254,6 +263,9 @@ def add(x1: array, x2: array, /) -> array: - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -308,6 +320,9 @@ def asin(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -370,6 +385,9 @@ def asinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -419,6 +437,9 @@ def atan(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -541,6 +562,9 @@ def atanh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -709,6 +733,8 @@ def conj(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have the same data type as ``x``. + + .. versionadded:: 2022.12 """ @@ -753,6 +779,9 @@ def cos(x: array, /) -> array: - If ``x_i`` is ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -813,6 +842,9 @@ def cosh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -893,6 +925,9 @@ def divide(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -934,6 +969,9 @@ def equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -987,6 +1025,9 @@ def exp(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1043,6 +1084,9 @@ def expm1(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1192,6 +1236,8 @@ def imag(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + .. versionadded:: 2022.12 """ @@ -1226,6 +1272,9 @@ def isfinite(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1258,6 +1307,9 @@ def isinf(x: array, /) -> array: - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1289,6 +1341,9 @@ def isnan(x: array, /) -> array: - If ``a`` or ``b`` is ``NaN``, the result is ``True``. - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1390,6 +1445,9 @@ def log(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1449,6 +1507,9 @@ def log1p(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1488,6 +1549,9 @@ def log2(x: array, /) -> array: \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1527,6 +1591,9 @@ def log10(x: array, /) -> array: \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1703,6 +1770,9 @@ def multiply(x1: array, x2: array, /) -> array: .. note:: For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1725,6 +1795,12 @@ def negative(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1764,6 +1840,9 @@ def not_equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1780,6 +1859,12 @@ def positive(x: array, /) -> array: ------- out: array an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1847,6 +1932,9 @@ def pow(x1: array, x2: array, /) -> array: .. note:: Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -1863,6 +1951,10 @@ def real(x: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + .. versionadded:: 2022.12 """ @@ -1958,6 +2050,9 @@ def round(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2002,6 +2097,9 @@ def sign(x: array, /) -> array: - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2045,6 +2143,9 @@ def sin(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2105,6 +2206,9 @@ def sinh(x: array, /) -> array: - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2133,6 +2237,9 @@ def square(x: array, /) -> array: **Special cases** For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2189,6 +2296,9 @@ def sqrt(x: array, /) -> array: - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2209,6 +2319,12 @@ def subtract(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2252,6 +2368,9 @@ def tan(x: array, /) -> array: - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -2316,6 +2435,9 @@ def tanh(x: array, /) -> array: For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index 2eb428b0c..7979095fe 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -44,6 +44,11 @@ def fft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -90,6 +95,11 @@ def ifft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -143,6 +153,11 @@ def fftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -196,6 +211,11 @@ def ifftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -242,6 +262,11 @@ def rfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -288,6 +313,11 @@ def irfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -341,6 +371,11 @@ def rfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -394,6 +429,11 @@ def irfftn( ------- out: array an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -437,6 +477,11 @@ def hfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -480,6 +525,11 @@ def ihfft( ------- out: array an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -507,6 +557,11 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar ------- out: array an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -536,6 +591,11 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a ------- out: array an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -559,6 +619,11 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ @@ -580,6 +645,11 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ------- out: array the shifted array. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 """ diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index b040251dd..3f6de3a58 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -38,6 +38,12 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: ------- out: array an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -65,6 +71,14 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: out: array an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** @@ -87,6 +101,12 @@ def det(x: array, /) -> array: ------- out: array if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -154,9 +174,14 @@ def eigh(x: array, /) -> Tuple[array]: - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -192,9 +217,14 @@ def eigvalsh(x: array, /) -> array: out: array an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + Notes + ----- .. note:: Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -224,6 +254,12 @@ def inv(x: array, /) -> array: ------- out: array an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -288,6 +324,12 @@ def matrix_norm( ------- out: array an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -306,6 +348,12 @@ def matrix_power(x: array, n: int, /) -> array: ------- out: array if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -326,6 +374,12 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a ------- out: array an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -348,6 +402,12 @@ def outer(x1: array, x2: array, /) -> array: ------- out: array a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -382,6 +442,12 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: ------- out: array an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -441,6 +507,12 @@ def qr( - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -490,6 +562,12 @@ def slogdet(x: array, /) -> Tuple[array, array]: - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -522,6 +600,12 @@ def solve(x1: array, x2: array, /) -> array: ------- out: array an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -571,6 +655,12 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -589,6 +679,12 @@ def svdvals(x: array, /) -> array: ------- out: array an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -653,6 +749,9 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -716,6 +815,12 @@ def vector_norm( ------- out: array an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py index c8b6e50f8..6590d2146 100644 --- a/src/array_api_stubs/_2022_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2022_12/linear_algebra_functions.py @@ -32,6 +32,11 @@ def matmul(x1: array, x2: array, /) -> array: The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** @@ -101,6 +106,12 @@ def tensordot( ------- out: array an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -133,6 +144,11 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: out: array if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. **Raises** diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py index 9393ba71e..9dcc0f95c 100644 --- a/src/array_api_stubs/_2022_12/searching_functions.py +++ b/src/array_api_stubs/_2022_12/searching_functions.py @@ -75,6 +75,12 @@ def nonzero(x: array, /) -> Tuple[array, ...]: ------- out: Typle[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/set_functions.py b/src/array_api_stubs/_2022_12/set_functions.py index dc95f58e8..661d3df90 100644 --- a/src/array_api_stubs/_2022_12/set_functions.py +++ b/src/array_api_stubs/_2022_12/set_functions.py @@ -38,6 +38,12 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -74,6 +80,12 @@ def unique_counts(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -110,6 +122,12 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -141,6 +159,12 @@ def unique_values(x: array, /) -> array: .. note:: The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/statistical_functions.py b/src/array_api_stubs/_2022_12/statistical_functions.py index 787faeeb9..93faaf31e 100644 --- a/src/array_api_stubs/_2022_12/statistical_functions.py +++ b/src/array_api_stubs/_2022_12/statistical_functions.py @@ -171,6 +171,9 @@ def prod( - If ``N`` is ``0``, the product is `1` (i.e., the empty product). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -265,6 +268,9 @@ def sum( - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_2022_12/utility_functions.py b/src/array_api_stubs/_2022_12/utility_functions.py index e70fe8aa6..64e5de297 100644 --- a/src/array_api_stubs/_2022_12/utility_functions.py +++ b/src/array_api_stubs/_2022_12/utility_functions.py @@ -33,6 +33,12 @@ def all( ------- out: array if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ @@ -68,6 +74,12 @@ def any( ------- out: array if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. """ From 73c7fcb0793a0a1f7c603bf444fb7e0ccab281fe Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Apr 2023 00:37:35 -0700 Subject: [PATCH 381/551] Apply suggestions from code review --- spec/draft/design_topics/exceptions.rst | 12 ++++++------ src/array_api_stubs/_draft/manipulation_functions.py | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/draft/design_topics/exceptions.rst b/spec/draft/design_topics/exceptions.rst index 0a176c302..570fe56e3 100644 --- a/spec/draft/design_topics/exceptions.rst +++ b/spec/draft/design_topics/exceptions.rst @@ -5,23 +5,23 @@ Exceptions This standard specifies expected syntax and semantics for a set of APIs. When inputs to an API do not match what is expected, libraries may emit warnings, -raise exceptions, or misbehave in unexpected ways. In general it is not +raise exceptions, or misbehave in unexpected ways. In general, it is not possible to foresee or specify all the ways in which unexpected or invalid inputs are provided. Therefore, this standard does not attempt to specify exception or warning types to the extent needed in order to do exception handling in a portable manner. In general, it is expected that array library implementers follow `the guidance given by the documentation of the Python -language `__, and use either -fitting builtin exception or warning types that are appropriate for the -situation, or custom exceptions or warnings that derive from those builtin +language `__, and either use +builtin exception or warning types that are appropriate for the +situation or use custom exceptions or warnings that derive from those builtin ones. In specific cases, it may be useful to provide guidance to array library authors regarding what an appropriate exception is. That guidance will be phrased as *should* rather than *must* (typically in a *Raises* section), because (a) there may be reasons for an implementer to deviate, and (b) more -often than not existing array library implementation already differ in their -choices and it may not be worth them breaking backwards compatibility in order +often than not, existing array library implementation already differ in their +choices, and it may not be worth them breaking backward compatibility in order to comply with a "must" in this standard. In other cases, this standard will only specify that an exception should or diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2a4b612f5..99a40057a 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -130,7 +130,7 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying if possible, and may copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. Returns ------- @@ -190,8 +190,8 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: Raises ------ ValueError - If a specified axis has a size greater than one, i.e. it is not a - singleton dimension, a ``ValueError`` should be raised. + If a specified axis has a size greater than one (i.e., it is not a + singleton dimension), a ``ValueError`` should be raised. """ From fcd54b380391e459ed9cb3449e4ce41a9e837243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Tue, 18 Apr 2023 17:09:15 -0600 Subject: [PATCH 382/551] Fix a typo in tensordot --- src/array_api_stubs/_draft/linear_algebra_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index 9d949c067..d9ac2437c 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -97,7 +97,7 @@ def tensordot( - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. .. note:: From 6dea842a0195da72e497b9a66cee3a0fe5243542 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Thu, 20 Apr 2023 17:28:26 -0500 Subject: [PATCH 383/551] Backport typo fix in tensordot (#624) --- src/array_api_stubs/_2021_12/linear_algebra_functions.py | 2 +- src/array_api_stubs/_2022_12/linear_algebra_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2021_12/linear_algebra_functions.py b/src/array_api_stubs/_2021_12/linear_algebra_functions.py index 30d09c254..a2defaf1b 100644 --- a/src/array_api_stubs/_2021_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2021_12/linear_algebra_functions.py @@ -75,7 +75,7 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. Returns ------- diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py index 6590d2146..110a19ce1 100644 --- a/src/array_api_stubs/_2022_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2022_12/linear_algebra_functions.py @@ -96,7 +96,7 @@ def tensordot( - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. .. note:: From 4d1372b85565101f4ddede1fa7ab4bdfc4680457 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 2 May 2023 11:29:57 -0500 Subject: [PATCH 384/551] Update all contributors (#618) --- .all-contributorsrc | 314 +++++++++++++++++++++++++++++++++++++++++++- README.md | 126 ++++++++++++------ 2 files changed, 396 insertions(+), 44 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 3bacaeb2f..f7f25e7d4 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -171,9 +171,7 @@ "avatar_url": "https://avatars.githubusercontent.com/u/2626883?v=4", "profile": "https://www.linkedin.com/in/shengzha/", "contributions": [ - "ideas", - "review", - "talk" + "ideas" ] }, { @@ -308,6 +306,316 @@ "contributions": [ "ideas" ] + }, + { + "login": "lezcano", + "name": "Mario Lezcano Casado", + "avatar_url": "https://avatars.githubusercontent.com/u/3291265?v=4", + "profile": "https://github.com/lezcano", + "contributions": [ + "ideas" + ] + }, + { + "login": "BvB93", + "name": "Bas van Beek", + "avatar_url": "https://avatars.githubusercontent.com/u/43369155?v=4", + "profile": "https://github.com/BvB93", + "contributions": [ + "ideas" + ] + }, + { + "login": "seberg", + "name": "Sebastian Berg", + "avatar_url": "https://avatars.githubusercontent.com/u/61977?v=4", + "profile": "https://github.com/seberg", + "contributions": [ + "ideas" + ] + }, + { + "login": "IsaacBreen", + "name": "Isaac Breen", + "avatar_url": "https://avatars.githubusercontent.com/u/57783927?v=4", + "profile": "https://github.com/IsaacBreen", + "contributions": [ + "ideas" + ] + }, + { + "login": "kmaehashi", + "name": "Kenichi Maehashi", + "avatar_url": "https://avatars.githubusercontent.com/u/939877?v=4", + "profile": "https://github.com/kmaehashi", + "contributions": [ + "ideas" + ] + }, + { + "login": "cnpryer", + "name": "Chris Pryer", + "avatar_url": "https://avatars.githubusercontent.com/u/14341145?v=4", + "profile": "https://github.com/cnpryer", + "contributions": [ + "ideas" + ] + }, + { + "login": "tirthasheshpatel", + "name": "Tirth Patel", + "avatar_url": "https://avatars.githubusercontent.com/u/43181252?v=4", + "profile": "https://github.com/tirthasheshpatel", + "contributions": [ + "ideas" + ] + }, + { + "login": "kshitij12345", + "name": "Kshiteej K", + "avatar_url": "https://avatars.githubusercontent.com/u/19503980?v=4", + "profile": "https://github.com/kshitij12345", + "contributions": [ + "ideas" + ] + }, + { + "login": "AnirudhDagar", + "name": "Anirudh Dagar", + "avatar_url": "https://avatars.githubusercontent.com/u/23621655?v=4", + "profile": "https://anirudhdagar.ml/", + "contributions": [ + "ideas" + ] + }, + { + "login": "tomwhite", + "name": "Tom White", + "avatar_url": "https://avatars.githubusercontent.com/u/85085?v=4", + "profile": "http://tom-e-white.com/", + "contributions": [ + "ideas" + ] + }, + { + "login": "honno", + "name": "Matthew Barber", + "avatar_url": "https://avatars.githubusercontent.com/u/8246949?v=4", + "profile": "https://github.com/honno", + "contributions": [ + "ideas", + "content" + ] + }, + { + "login": "pmeier", + "name": "Philip Meier", + "avatar_url": "https://avatars.githubusercontent.com/u/6849766?v=4", + "profile": "https://github.com/pmeier", + "contributions": [ + "research", + "code" + ] + }, + { + "login": "Zac-HD", + "name": "Zac Hatfield-Dodds", + "avatar_url": "https://avatars.githubusercontent.com/u/12229877?v=4", + "profile": "https://github.com/Zac-HD", + "contributions": [ + "ideas", + "code" + ] + }, + { + "login": "djl11", + "name": "Daniel Lenton", + "avatar_url": "https://avatars.githubusercontent.com/u/22750088?v=4", + "profile": "https://github.com/djl11", + "contributions": [ + "code" + ] + }, + { + "login": "simonetgordon", + "name": "Simone G", + "avatar_url": "https://avatars.githubusercontent.com/u/74716948?v=4", + "profile": "https://github.com/simonetgordon", + "contributions": [ + "code", + "ideas" + ] + }, + { + "login": "tylerjereddy", + "name": "Tyler Reddy", + "avatar_url": "https://avatars.githubusercontent.com/u/7903078?v=4", + "profile": "https://github.com/tylerjereddy", + "contributions": [ + "ideas" + ] + }, + { + "login": "mattbarrett98", + "name": "Matt Barrett", + "avatar_url": "https://avatars.githubusercontent.com/u/83289589?v=4", + "profile": "https://github.com/mattbarrett98", + "contributions": [ + "ideas" + ] + }, + { + "login": "bicycleman15", + "name": "Jatin Prakash", + "avatar_url": "https://avatars.githubusercontent.com/u/47978882?v=4", + "profile": "https://github.com/bicycleman15", + "contributions": [ + "ideas" + ] + }, + { + "login": "Ishticode", + "name": "Ishtiaq Hussain", + "avatar_url": "https://avatars.githubusercontent.com/u/53497039?v=4", + "profile": "https://github.com/Ishticode", + "contributions": [ + "ideas" + ] + }, + { + "login": "sherry30", + "name": "sherry30", + "avatar_url": "https://avatars.githubusercontent.com/u/65318415?v=4", + "profile": "https://github.com/sherry30", + "contributions": [ + "ideas" + ] + }, + { + "login": "juaolobo", + "name": "João Lobo", + "avatar_url": "https://avatars.githubusercontent.com/u/49628984?v=4", + "profile": "https://github.com/juaolobo", + "contributions": [ + "ideas" + ] + }, + { + "login": "NeilGirdhar", + "name": "Neil Girdhar", + "avatar_url": "https://avatars.githubusercontent.com/u/730137?v=4", + "profile": "https://github.com/NeilGirdhar", + "contributions": [ + "ideas" + ] + }, + { + "login": "nstarman", + "name": "Nathaniel Starkman", + "avatar_url": "https://avatars.githubusercontent.com/u/8949649?v=4", + "profile": "https://github.com/nstarman", + "contributions": [ + "ideas" + ] + }, + { + "login": "jakirkham", + "name": "jakirkham", + "avatar_url": "https://avatars.githubusercontent.com/u/3019665?v=4", + "profile": "https://github.com/jakirkham", + "contributions": [ + "ideas" + ] + }, + { + "login": "RickSanchezStoic", + "name": "RickSanchezStoic", + "avatar_url": "https://avatars.githubusercontent.com/u/57310695?v=4", + "profile": "https://github.com/RickSanchezStoic", + "contributions": [ + "ideas" + ] + }, + { + "login": "tlambert03", + "name": "Talley Lambert", + "avatar_url": "https://avatars.githubusercontent.com/u/1609449?v=4", + "profile": "https://github.com/tlambert03", + "contributions": [ + "ideas" + ] + }, + { + "login": "jni", + "name": "Juan Nunez-Iglesias", + "avatar_url": "https://avatars.githubusercontent.com/u/492549?v=4", + "profile": "http://ilovesymposia.com/", + "contributions": [ + "ideas" + ] + }, + { + "login": "chkothe", + "name": "Christian Kothe", + "avatar_url": "https://avatars.githubusercontent.com/u/5318120?v=4", + "profile": "https://github.com/chkothe", + "contributions": [ + "ideas" + ] + }, + { + "login": "vnmabus", + "name": "Carlos Ramos Carreño", + "avatar_url": "https://avatars.githubusercontent.com/u/2364173?v=4", + "profile": "https://github.com/vnmabus", + "contributions": [ + "ideas" + ] + }, + { + "login": "gilfree", + "name": "Gilad", + "avatar_url": "https://avatars.githubusercontent.com/u/88031955?v=4", + "profile": "https://github.com/gilfree", + "contributions": [ + "ideas" + ] + }, + { + "login": "thomasjpfan", + "name": "Thomas J. Fan", + "avatar_url": "https://avatars.githubusercontent.com/u/5402633?v=4", + "profile": "https://github.com/thomasjpfan", + "contributions": [ + "ideas" + ] + }, + { + "login": "Conchylicultor", + "name": "Conchylicultor", + "avatar_url": "https://avatars.githubusercontent.com/u/9047355?v=4", + "profile": "http://e-pot.xyz/", + "contributions": [ + "ideas" + ] + }, + { + "login": "fcharras", + "name": "Franck Charras", + "avatar_url": "https://avatars.githubusercontent.com/u/29153872?v=4", + "profile": "https://github.com/fcharras", + "contributions": [ + "ideas" + ] + }, + { + "login": "kkraus14", + "name": "Keith Kraus", + "avatar_url": "https://avatars.githubusercontent.com/u/3665167?v=4", + "profile": "https://github.com/kkraus14", + "contributions": [ + "ideas" + ] } ], "contributorsPerLine": 7 diff --git a/README.md b/README.md index 6c32aec19..dbfee4cea 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Array API standard -[![All Contributors](https://img.shields.io/badge/all_contributors-29-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-63-orange.svg?style=flat-square)](#contributors-) This repository contains documents, tooling and other content related to the @@ -151,45 +151,89 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Saul Shanabrook

🔧 🤔 🔬

Athan

🖋 🔣 🔧 🔬

Stephannie Jimenez Gacha

🔣 🖋 🔬

Aaron Meurer

🖋 ⚠️ 🔧

Tony Fast

🚧

Ralf Gommers

📝 💼 💻 🖋 📖 🔍 🚧 🤔 📆 📢

Travis E. Oliphant

💼 🔍 🤔

Leo Fang

👀 🤔 🖋

Tianqi Chen

🤔 👀

Stephan Hoyer

🤔 👀 💬

Alexandre Passos

🤔 👀

Paige Bailey

🔍

Adam Paszke

🤔 👀 📢

Andreas Mueller

🤔 👀

Sheng Zha

🤔 👀 📢

kkraus

🤔 👀 📢

Tom Augspurger

👀 💬

edloper

👀 💬

Areg Melik-Adamyan

👀 🔍

Oleksandr Pavlyk

👀 💬

tdimitri

🤔

Jack Pappas

🤔

Ashish Agarwal

👀 💬

Edward Z. Yang

🤔

Mike Ruberry

🤔

Eric Wieser

🤔

Carol Willing

🤔

Alex Rogozhnikov

🤔

Matthew Honnibal

🤔
Saul Shanabrook
Saul Shanabrook

🔧 🤔 🔬
Athan
Athan

🖋 🔣 🔧 🔬
Stephannie Jimenez Gacha
Stephannie Jimenez Gacha

🔣 🖋 🔬
Aaron Meurer
Aaron Meurer

🖋 ⚠️ 🔧
Tony Fast
Tony Fast

🚧
Ralf Gommers
Ralf Gommers

📝 💼 💻 🖋 📖 🔍 🚧 🤔 📆 📢
Travis E. Oliphant
Travis E. Oliphant

💼 🔍 🤔
Leo Fang
Leo Fang

👀 🤔 🖋
Tianqi Chen
Tianqi Chen

🤔 👀
Stephan Hoyer
Stephan Hoyer

🤔 👀 💬
Alexandre Passos
Alexandre Passos

🤔 👀
Paige Bailey
Paige Bailey

🔍
Adam Paszke
Adam Paszke

🤔 👀 📢
Andreas Mueller
Andreas Mueller

🤔 👀
Sheng Zha
Sheng Zha

🤔
kkraus
kkraus

🤔 👀 📢
Tom Augspurger
Tom Augspurger

👀 💬
edloper
edloper

👀 💬
Areg Melik-Adamyan
Areg Melik-Adamyan

👀 🔍
Oleksandr Pavlyk
Oleksandr Pavlyk

👀 💬
tdimitri
tdimitri

🤔
Jack Pappas
Jack Pappas

🤔
Ashish Agarwal
Ashish Agarwal

👀 💬
Edward Z. Yang
Edward Z. Yang

🤔
Mike Ruberry
Mike Ruberry

🤔
Eric Wieser
Eric Wieser

🤔
Carol Willing
Carol Willing

🤔
Alex Rogozhnikov
Alex Rogozhnikov

🤔
Matthew Honnibal
Matthew Honnibal

🤔
Mario Lezcano Casado
Mario Lezcano Casado

🤔
Bas van Beek
Bas van Beek

🤔
Sebastian Berg
Sebastian Berg

🤔
Isaac Breen
Isaac Breen

🤔
Kenichi Maehashi
Kenichi Maehashi

🤔
Chris Pryer
Chris Pryer

🤔
Tirth Patel
Tirth Patel

🤔
Kshiteej K
Kshiteej K

🤔
Anirudh Dagar
Anirudh Dagar

🤔
Tom White
Tom White

🤔
Matthew Barber
Matthew Barber

🤔 🖋
Philip Meier
Philip Meier

🔬 💻
Zac Hatfield-Dodds
Zac Hatfield-Dodds

🤔 💻
Daniel Lenton
Daniel Lenton

💻
Simone G
Simone G

💻 🤔
Tyler Reddy
Tyler Reddy

🤔
Matt Barrett
Matt Barrett

🤔
Jatin Prakash
Jatin Prakash

🤔
Ishtiaq Hussain
Ishtiaq Hussain

🤔
sherry30
sherry30

🤔
João Lobo
João Lobo

🤔
Neil Girdhar
Neil Girdhar

🤔
Nathaniel Starkman
Nathaniel Starkman

🤔
jakirkham
jakirkham

🤔
RickSanchezStoic
RickSanchezStoic

🤔
Talley Lambert
Talley Lambert

🤔
Juan Nunez-Iglesias
Juan Nunez-Iglesias

🤔
Christian Kothe
Christian Kothe

🤔
Carlos Ramos Carreño
Carlos Ramos Carreño

🤔
Gilad
Gilad

🤔
Thomas J. Fan
Thomas J. Fan

🤔
Conchylicultor
Conchylicultor

🤔
Franck Charras
Franck Charras

🤔
Keith Kraus
Keith Kraus

🤔
@@ -197,4 +241,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! \ No newline at end of file From accf8c20d8fae9b760e59a40ab43b556fd8410cb Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Tue, 2 May 2023 11:32:41 -0500 Subject: [PATCH 385/551] Fix `svd` function return dtype (#619) --- src/array_api_stubs/_2021_12/linalg.py | 4 ++-- src/array_api_stubs/_2022_12/linalg.py | 4 ++-- src/array_api_stubs/_draft/linalg.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 0749daf8e..230645439 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -364,7 +364,7 @@ def solve(x1: array, x2: array, /) -> array: an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. """ -def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: """ Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) ``x``, where ``U`` is a matrix (or a stack of matrices) with orthonormal columns, ``S`` is a vector of non-negative numbers (or stack of vectors), and ``Vh`` is a matrix (or a stack of matrices) with orthonormal rows. @@ -379,7 +379,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ------- .. NOTE: once complex numbers are supported, each square matrix must be Hermitian. - out: Union[array, Tuple[array, ...]] + out: Tuple[array, array, array] a namedtuple ``(U, S, Vh)`` whose - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index 3f6de3a58..c1ff64c3e 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -609,7 +609,7 @@ def solve(x1: array, x2: array, /) -> array: """ -def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: r""" Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. @@ -649,7 +649,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, Returns ------- - out: Union[array, Tuple[array, ...]] + out: Tuple[array, array, array] a namedtuple ``(U, S, Vh)`` whose - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 20d1d54ff..b03f6eb63 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -609,7 +609,7 @@ def solve(x1: array, x2: array, /) -> array: """ -def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, ...]]: +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: r""" Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. @@ -649,7 +649,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Union[array, Tuple[array, Returns ------- - out: Union[array, Tuple[array, ...]] + out: Tuple[array, array, array] a namedtuple ``(U, S, Vh)`` whose - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. From d0353d9150db2b94ec807467fc5b8c8c882a6199 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:09:36 +0200 Subject: [PATCH 386/551] Modify function to remain in the same page if the version is changed --- spec/_static/javascripts/version_dropdown.js | 31 ++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 spec/_static/javascripts/version_dropdown.js diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js new file mode 100644 index 000000000..df7a496e9 --- /dev/null +++ b/spec/_static/javascripts/version_dropdown.js @@ -0,0 +1,31 @@ +function add_custom_version_dropdown(json_loc, target_loc, text) { + + var dropdown = document.createElement("div"); + dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; + var button = document.createElement("button"); + button.className = "dropdownbutton"; + var content = document.createElement("div"); + content.className = "dropdown-content md-hero"; + dropdown.appendChild(button); + dropdown.appendChild(content); + console.log('*********'); + $.getJSON(json_loc, function(versions) { + for (var key in versions) { + if (versions.hasOwnProperty(key)) { + console.log(key, versions[key]); + var a = document.createElement("a"); + a.innerHTML = key; + a.title = key; + a.href = target_loc + versions[key] + "/{{ pagename }}.html"; + console.log('----', a.href); + content.appendChild(a); + } + } + }).done(function() { + button.innerHTML = text; + }).fail(function() { + button.innerHTML = "Other Versions Not Found"; + }).always(function() { + $(".navheader").append(dropdown); + }); +}; From 395f34246cd8392332a01b0c29f439ab5dc614a4 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:18:42 +0200 Subject: [PATCH 387/551] Rename function --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index df7a496e9..c9d5248d2 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,4 +1,4 @@ -function add_custom_version_dropdown(json_loc, target_loc, text) { +function add_version_dropdown(json_loc, target_loc, text) { var dropdown = document.createElement("div"); dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; From 4ab650d10b428b3010c13d8659bab09c95a86ced Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:33:01 +0200 Subject: [PATCH 388/551] Fix current url path --- spec/_static/javascripts/version_dropdown.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index c9d5248d2..5fe84e4cb 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -13,10 +13,12 @@ function add_version_dropdown(json_loc, target_loc, text) { for (var key in versions) { if (versions.hasOwnProperty(key)) { console.log(key, versions[key]); + var currentURL = window.location.href; + var path = currentURL.split( versions[key] )[ 1 ]; var a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = target_loc + versions[key] + "/{{ pagename }}.html"; + a.href = target_loc + versions[key] + path; console.log('----', a.href); content.appendChild(a); } From 4d941c9d425c59d37a7fd0b3718d6e7d042cb608 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:46:18 +0200 Subject: [PATCH 389/551] Fix URL --- spec/_static/javascripts/version_dropdown.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 5fe84e4cb..3a01a4695 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -10,15 +10,18 @@ function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(content); console.log('*********'); $.getJSON(json_loc, function(versions) { + var currentURL = window.location.href; + var path = currentURL.split( "_site" )[ 1 ]; + path = path.split('/'); + path = path.slice(1, path.length); + path = path.join('/'); for (var key in versions) { if (versions.hasOwnProperty(key)) { console.log(key, versions[key]); - var currentURL = window.location.href; - var path = currentURL.split( versions[key] )[ 1 ]; var a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = target_loc + versions[key] + path; + a.href = target_loc + versions[key] + "/" + path; console.log('----', a.href); content.appendChild(a); } From b8c053dd1cff1020fb961e1ba72ab66563c2c17a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 01:53:19 +0200 Subject: [PATCH 390/551] fix index --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 3a01a4695..097b27bd4 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -13,7 +13,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var currentURL = window.location.href; var path = currentURL.split( "_site" )[ 1 ]; path = path.split('/'); - path = path.slice(1, path.length); + path = path.slice(2, path.length); path = path.join('/'); for (var key in versions) { if (versions.hasOwnProperty(key)) { From 11dbf7834c3759c6643a13f8814db11273a1598d Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 02:08:44 +0200 Subject: [PATCH 391/551] Check if the page exists before assigning href --- spec/_static/javascripts/version_dropdown.js | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 097b27bd4..0093dfd64 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -21,9 +21,22 @@ function add_version_dropdown(json_loc, target_loc, text) { var a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = target_loc + versions[key] + "/" + path; - console.log('----', a.href); - content.appendChild(a); + var url = target_loc + versions[key]; + var http = new XMLHttpRequest(); + http.open('HEAD', url + "/" + path ); + http.onreadystatechange = function() { + if (this.readyState == this.DONE) { + callback(this.status != 404); + if(this.status != 404 ){ + a.href = url + "/" + path; + } + else { + a.href = url; + } + content.appendChild(a); + } + }; + http.send(); } } }).done(function() { From 5b1be4c00116cea291ca0efbfd1e79c52106b824 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 02:17:15 +0200 Subject: [PATCH 392/551] remove callback --- spec/_static/javascripts/version_dropdown.js | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 0093dfd64..db14796b4 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -26,7 +26,6 @@ function add_version_dropdown(json_loc, target_loc, text) { http.open('HEAD', url + "/" + path ); http.onreadystatechange = function() { if (this.readyState == this.DONE) { - callback(this.status != 404); if(this.status != 404 ){ a.href = url + "/" + path; } From 50424b86e49b2cbd31e2f04964ec734664076feb Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 02:24:18 +0200 Subject: [PATCH 393/551] change head to get --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index db14796b4..e0b10ee46 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -23,7 +23,7 @@ function add_version_dropdown(json_loc, target_loc, text) { a.title = key; var url = target_loc + versions[key]; var http = new XMLHttpRequest(); - http.open('HEAD', url + "/" + path ); + http.open('GET', url + "/" + path ); http.onreadystatechange = function() { if (this.readyState == this.DONE) { if(this.status != 404 ){ From 96b426f51ba016a12ae0068a0a0e6281fed67b40 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 14:38:17 +0200 Subject: [PATCH 394/551] Move appendChild --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e0b10ee46..ac375f426 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -32,10 +32,10 @@ function add_version_dropdown(json_loc, target_loc, text) { else { a.href = url; } - content.appendChild(a); } }; http.send(); + content.appendChild(a); } } }).done(function() { From a6157d04d7ec81aa4dfbc8635583a38eab5a3035 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 14:47:24 +0200 Subject: [PATCH 395/551] Add print --- spec/_static/javascripts/version_dropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index ac375f426..db5e0fa26 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -25,6 +25,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var http = new XMLHttpRequest(); http.open('GET', url + "/" + path ); http.onreadystatechange = function() { + console.log('%%%%', this); if (this.readyState == this.DONE) { if(this.status != 404 ){ a.href = url + "/" + path; From 7a4c0a494a2886e6a18fc1df98be6a485036a294 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 15:59:56 +0200 Subject: [PATCH 396/551] split function --- spec/_static/javascripts/version_dropdown.js | 34 +++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index db5e0fa26..a75ede5a2 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,5 +1,21 @@ -function add_version_dropdown(json_loc, target_loc, text) { +function assign_href( a ) { + var http = new XMLHttpRequest(); + http.open('GET', url + "/" + path ); + http.onreadystatechange = function() { + console.log('%%%%', this); + if (this.readyState == this.DONE) { + if(this.status != 404 ){ + a.href = url + "/" + path; + } + else { + a.href = url; + } + } + }; + http.send(); +} +function add_version_dropdown(json_loc, target_loc, text) { var dropdown = document.createElement("div"); dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; var button = document.createElement("button"); @@ -21,21 +37,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var a = document.createElement("a"); a.innerHTML = key; a.title = key; - var url = target_loc + versions[key]; - var http = new XMLHttpRequest(); - http.open('GET', url + "/" + path ); - http.onreadystatechange = function() { - console.log('%%%%', this); - if (this.readyState == this.DONE) { - if(this.status != 404 ){ - a.href = url + "/" + path; - } - else { - a.href = url; - } - } - }; - http.send(); + assign_href( a ); content.appendChild(a); } } From 24c1479baba16188ad756621d1c6c9ba0b1c312a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 16:10:21 +0200 Subject: [PATCH 397/551] fix missing variable --- spec/_static/javascripts/version_dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a75ede5a2..a2f72f23e 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,4 +1,4 @@ -function assign_href( a ) { +function assign_href( a, url, path ) { var http = new XMLHttpRequest(); http.open('GET', url + "/" + path ); http.onreadystatechange = function() { @@ -37,7 +37,7 @@ function add_version_dropdown(json_loc, target_loc, text) { var a = document.createElement("a"); a.innerHTML = key; a.title = key; - assign_href( a ); + assign_href( a, target_loc + versions[key], path ); content.appendChild(a); } } From f649007e2aab3cd7ec203906fbadf478e016c79f Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 10 May 2023 16:23:30 +0200 Subject: [PATCH 398/551] move print --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a2f72f23e..ccd33f214 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -2,9 +2,9 @@ function assign_href( a, url, path ) { var http = new XMLHttpRequest(); http.open('GET', url + "/" + path ); http.onreadystatechange = function() { - console.log('%%%%', this); if (this.readyState == this.DONE) { if(this.status != 404 ){ + console.log('%%%%', this); a.href = url + "/" + path; } else { From 45ae354a946543648b28da4fe58f50afa1e87de8 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 24 May 2023 22:44:36 -0600 Subject: [PATCH 399/551] Fix invalid escape sequences in some files (#632) These can be found with the command python -We:invalid -We::SyntaxWarning -m compileall -f -q src/ --- src/array_api_stubs/_2021_12/creation_functions.py | 2 +- src/array_api_stubs/_2021_12/elementwise_functions.py | 4 ++-- src/array_api_stubs/_2021_12/linalg.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index 3285a386d..4ee683cd9 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -29,7 +29,7 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None """ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: - """ + r""" Convert the input to an array. Parameters diff --git a/src/array_api_stubs/_2021_12/elementwise_functions.py b/src/array_api_stubs/_2021_12/elementwise_functions.py index 213ebe53e..bf831d304 100644 --- a/src/array_api_stubs/_2021_12/elementwise_functions.py +++ b/src/array_api_stubs/_2021_12/elementwise_functions.py @@ -598,7 +598,7 @@ def floor(x: array, /) -> array: """ def floor_divide(x1: array, x2: array, /) -> array: - """ + r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. .. note:: @@ -1390,4 +1390,4 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] \ No newline at end of file +__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 230645439..6a0348129 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -444,7 +444,7 @@ def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: - """ + r""" Computes the vector norm of a vector (or batch of vectors) ``x``. Parameters From 0d85fa73bb121bf8788134e2f0be9ad5a632d677 Mon Sep 17 00:00:00 2001 From: Felix Hirwa Nshuti Date: Wed, 31 May 2023 04:15:50 +0000 Subject: [PATCH 400/551] typo fix in abs rfc --- src/array_api_stubs/_2022_12/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index b502e091b..28768e9d9 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -30,7 +30,7 @@ def abs(x: array, /) -> array: Returns ------- out: array - an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). Notes ----- From aee9df3496dca02ce90295b56fd2afa50971fb52 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 30 May 2023 21:29:01 -0700 Subject: [PATCH 401/551] Fix type in absolute value return value description --- src/array_api_stubs/_draft/elementwise_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 74ef7e98d..5f474e7c8 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -30,7 +30,7 @@ def abs(x: array, /) -> array: Returns ------- out: array - an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). Notes ----- From 18b776358c772d167d54780a795d9d356121ca3a Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Mon, 5 Jun 2023 19:01:32 -0600 Subject: [PATCH 402/551] Add missing dtype attribute to iinfo_object and finfo_object --- src/array_api_stubs/_2022_12/_types.py | 4 ++-- src/array_api_stubs/_draft/_types.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/_types.py b/src/array_api_stubs/_2022_12/_types.py index 4a60040d5..589606784 100644 --- a/src/array_api_stubs/_2022_12/_types.py +++ b/src/array_api_stubs/_2022_12/_types.py @@ -39,7 +39,7 @@ class finfo_object: max: float min: float smallest_normal: float - + dtype: dtype @dataclass class iinfo_object: @@ -47,7 +47,7 @@ class iinfo_object: bits: int max: int min: int - + dtype: dtype _T_co = TypeVar("_T_co", covariant=True) diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 4a60040d5..589606784 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -39,7 +39,7 @@ class finfo_object: max: float min: float smallest_normal: float - + dtype: dtype @dataclass class iinfo_object: @@ -47,7 +47,7 @@ class iinfo_object: bits: int max: int min: int - + dtype: dtype _T_co = TypeVar("_T_co", covariant=True) From 13121939aa54fdfa10b47ccedd08995619f9522e Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:18:14 -0500 Subject: [PATCH 403/551] Use fetch API --- spec/_static/javascripts/version_dropdown.js | 22 ++++++++------------ 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index ccd33f214..44cd26db5 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,18 +1,14 @@ function assign_href( a, url, path ) { - var http = new XMLHttpRequest(); - http.open('GET', url + "/" + path ); - http.onreadystatechange = function() { - if (this.readyState == this.DONE) { - if(this.status != 404 ){ - console.log('%%%%', this); - a.href = url + "/" + path; - } - else { - a.href = url; - } + const r = fetch( url + "/" + path ); + r.then( response => { + console.log('...', response); + if( response.ok ){ + a.href = url + "/" + path; } - }; - http.send(); + else { + a.href = url; + } + }); } function add_version_dropdown(json_loc, target_loc, text) { From 8ca2b0f39a405deca8b5474b41602377dd278d9e Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:28:59 -0500 Subject: [PATCH 404/551] add catch block --- spec/_static/javascripts/version_dropdown.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 44cd26db5..99511b2f7 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -5,9 +5,8 @@ function assign_href( a, url, path ) { if( response.ok ){ a.href = url + "/" + path; } - else { - a.href = url; - } + }).catch( error => { + a.href = url; }); } From 5c73a1a0e16a554e7a7e0c11fd9df78e50dae165 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:39:00 -0500 Subject: [PATCH 405/551] add url if status is not ok --- spec/_static/javascripts/version_dropdown.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 99511b2f7..e92ea9082 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -5,6 +5,9 @@ function assign_href( a, url, path ) { if( response.ok ){ a.href = url + "/" + path; } + else { + a.href = url; + } }).catch( error => { a.href = url; }); From bac4929259e2b0b7965bccdce0f04eff373e6d21 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 11:48:22 -0500 Subject: [PATCH 406/551] remove prints and point to the index file --- spec/_static/javascripts/version_dropdown.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e92ea9082..e3608ab88 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,15 +1,14 @@ function assign_href( a, url, path ) { const r = fetch( url + "/" + path ); r.then( response => { - console.log('...', response); if( response.ok ){ a.href = url + "/" + path; } else { - a.href = url; + a.href = url + "/index.html"; } }).catch( error => { - a.href = url; + a.href = url + "/index.html"; }); } @@ -22,7 +21,6 @@ function add_version_dropdown(json_loc, target_loc, text) { content.className = "dropdown-content md-hero"; dropdown.appendChild(button); dropdown.appendChild(content); - console.log('*********'); $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; var path = currentURL.split( "_site" )[ 1 ]; From 9c024950369254335e23aee26aa23d4235daa828 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Mon, 3 Jul 2023 12:01:45 -0500 Subject: [PATCH 407/551] remove unused variable --- spec/_static/javascripts/version_dropdown.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e3608ab88..d255f8147 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,6 +1,5 @@ function assign_href( a, url, path ) { - const r = fetch( url + "/" + path ); - r.then( response => { + fetch( url + "/" + path ).then( response => { if( response.ok ){ a.href = url + "/" + path; } From 487fc3a0fb41550742a938d68f1e863e3cdbf828 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 8 Jul 2023 15:03:04 -0700 Subject: [PATCH 408/551] Use consistent style and remove console.log --- spec/_static/javascripts/version_dropdown.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d255f8147..9cfe8cc06 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,12 +1,11 @@ -function assign_href( a, url, path ) { - fetch( url + "/" + path ).then( response => { - if( response.ok ){ +function assign_href(a, url, path) { + fetch(url + "/" + path).then(response => { + if (response.ok){ a.href = url + "/" + path; - } - else { + } else { a.href = url + "/index.html"; } - }).catch( error => { + }).catch(error => { a.href = url + "/index.html"; }); } @@ -22,17 +21,16 @@ function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(content); $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; - var path = currentURL.split( "_site" )[ 1 ]; - path = path.split('/'); + var path = currentURL.split("_site")[1]; + path = path.split("/"); path = path.slice(2, path.length); - path = path.join('/'); + path = path.join("/"); for (var key in versions) { if (versions.hasOwnProperty(key)) { - console.log(key, versions[key]); var a = document.createElement("a"); a.innerHTML = key; a.title = key; - assign_href( a, target_loc + versions[key], path ); + assign_href(a, target_loc + versions[key], path); content.appendChild(a); } } From 44b35f6d240f68235d4e8dc0b70c8d6116ffd372 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 8 Jul 2023 15:03:25 -0700 Subject: [PATCH 409/551] Add space --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 9cfe8cc06..d43ddde52 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,6 +1,6 @@ function assign_href(a, url, path) { fetch(url + "/" + path).then(response => { - if (response.ok){ + if (response.ok) { a.href = url + "/" + path; } else { a.href = url + "/index.html"; From 41eb94ba794741edc07ae68ebee01961c90458a3 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 15:26:49 -0700 Subject: [PATCH 410/551] Ensure variable is defined --- spec/_static/javascripts/version_dropdown.js | 22 +++++++++++--------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d43ddde52..e4b79fd01 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -22,16 +22,18 @@ function add_version_dropdown(json_loc, target_loc, text) { $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; var path = currentURL.split("_site")[1]; - path = path.split("/"); - path = path.slice(2, path.length); - path = path.join("/"); - for (var key in versions) { - if (versions.hasOwnProperty(key)) { - var a = document.createElement("a"); - a.innerHTML = key; - a.title = key; - assign_href(a, target_loc + versions[key], path); - content.appendChild(a); + if (path) { + path = path.split("/"); + path = path.slice(2, path.length); + path = path.join("/"); + for (var key in versions) { + if (versions.hasOwnProperty(key)) { + var a = document.createElement("a"); + a.innerHTML = key; + a.title = key; + assign_href(a, target_loc + versions[key], path); + content.appendChild(a); + } } } }).done(function() { From 244796d37ce5dd00ae71cff3dea9730447058ad9 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 15:31:34 -0700 Subject: [PATCH 411/551] Accommodate both the preview and deployed site --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index e4b79fd01..ad54ff16b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -21,7 +21,7 @@ function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(content); $.getJSON(json_loc, function(versions) { var currentURL = window.location.href; - var path = currentURL.split("_site")[1]; + var path = currentURL.split(/_site|array_api/)[1]; if (path) { path = path.split("/"); path = path.slice(2, path.length); From 5c124b81711ac51ff45963b5c698308e48d8f475 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:03:34 -0700 Subject: [PATCH 412/551] Refactor to use async/await and update URL manipulation logic --- spec/_static/javascripts/version_dropdown.js | 122 +++++++++++++++---- 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index ad54ff16b..0b12c8005 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,46 +1,114 @@ -function assign_href(a, url, path) { - fetch(url + "/" + path).then(response => { +/** +* Returns a URL corresponding to a versioned resource (if one exists). +* +* @private +* @param {string} url - base URL +* @param {string} path - resource path +* @returns {Promise} promise which resolves a resource URL +*/ +async function href(url, path) { + const defaultURL = url + "/index.html"; + url += "/" + path; + await fetch(url).then(onResponse).catch(onError); + + /** + * Success handler. + * + * @private + * @param {Object} response - response object + */ + function onResponse(response) { if (response.ok) { - a.href = url + "/" + path; - } else { - a.href = url + "/index.html"; + return url; } - }).catch(error => { - a.href = url + "/index.html"; - }); + return defaultURL; + } + + /** + * Error handler. + * + * @private + * @param {Error} error - error object + */ + function onError(error) { + return defaultURL; + } } -function add_version_dropdown(json_loc, target_loc, text) { - var dropdown = document.createElement("div"); +/** +* Adds a version dropdown menu with custom URL paths depending on the current page. +* +* @param {string} json_loc - JSON URL +* @param {string} target_loc - target URL +* @param {string} text - text +* @returns {Promise} promise which resolves upon adding a version menu +*/ +async function add_version_dropdown(json_loc, target_loc, text) { + const dropdown = document.createElement("div"); dropdown.className = "md-flex__cell md-flex__cell--shrink dropdown"; - var button = document.createElement("button"); + + const button = document.createElement("button"); button.className = "dropdownbutton"; - var content = document.createElement("div"); + + const content = document.createElement("div"); content.className = "dropdown-content md-hero"; + dropdown.appendChild(button); dropdown.appendChild(content); - $.getJSON(json_loc, function(versions) { - var currentURL = window.location.href; - var path = currentURL.split(/_site|array_api/)[1]; + + await $.getJSON(json_loc, onVersions).done(onDone).fail(onFail).always(onAlways); + + /** + * Callback invoked upon successfully resolving a list of versions. + * + * @private + * @param {Object} versions - versions object + */ + async function onVersions(versions) { + const currentURL = window.location.href; + let path = currentURL.split(/_site|array_api/)[1]; if (path) { path = path.split("/"); path = path.slice(2, path.length); path = path.join("/"); - for (var key in versions) { - if (versions.hasOwnProperty(key)) { - var a = document.createElement("a"); - a.innerHTML = key; - a.title = key; - assign_href(a, target_loc + versions[key], path); - content.appendChild(a); - } + } else { + path = ""; + } + for (let key in versions) { + if (versions.hasOwnProperty(key)) { + let a = document.createElement("a"); + a.innerHTML = key; + a.title = key; + a.href = await href(target_loc + versions[key], path); + content.appendChild(a); } } - }).done(function() { + } + + /** + * Callback invoked upon resolving a JSON resource. + * + * @private + */ + function onDone() { button.innerHTML = text; - }).fail(function() { + } + + /** + * Callback invoked upon failing to resolve a JSON resource. + * + * @private + */ + function onFail() { button.innerHTML = "Other Versions Not Found"; - }).always(function() { + } + + /** + * Callback which is always invoked upon attempting to resolve a JSON resource. + * + * @private + */ + function onAlways() { $(".navheader").append(dropdown); - }); + } }; From e21b169eed58e70b2bc58f2acf6ddbc9044e9f72 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:29:49 -0700 Subject: [PATCH 413/551] Remove duplicate success callback --- spec/_static/javascripts/version_dropdown.js | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 0b12c8005..8a4371f97 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -56,15 +56,15 @@ async function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(button); dropdown.appendChild(content); - await $.getJSON(json_loc, onVersions).done(onDone).fail(onFail).always(onAlways); + await $.getJSON(json_loc).done(onDone).fail(onFail).always(onAlways); /** - * Callback invoked upon successfully resolving a list of versions. + * Callback invoked upon resolving a JSON resource. * * @private * @param {Object} versions - versions object */ - async function onVersions(versions) { + async function onDone(versions) { const currentURL = window.location.href; let path = currentURL.split(/_site|array_api/)[1]; if (path) { @@ -83,14 +83,6 @@ async function add_version_dropdown(json_loc, target_loc, text) { content.appendChild(a); } } - } - - /** - * Callback invoked upon resolving a JSON resource. - * - * @private - */ - function onDone() { button.innerHTML = text; } From 39d16db3a6ebc1cb595391d42d4d7558b26dbc46 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:33:51 -0700 Subject: [PATCH 414/551] Add comment --- spec/_static/javascripts/version_dropdown.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 8a4371f97..d126a6859 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -9,6 +9,8 @@ async function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; + + // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: await fetch(url).then(onResponse).catch(onError); /** From e4db25e4da0fcf358c821e845a3b5a9da6eb4909 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:34:36 -0700 Subject: [PATCH 415/551] Update function descriptions --- spec/_static/javascripts/version_dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d126a6859..c66d51c65 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -14,7 +14,7 @@ async function href(url, path) { await fetch(url).then(onResponse).catch(onError); /** - * Success handler. + * Callback invoked upon successfully resolving a resource. * * @private * @param {Object} response - response object @@ -27,7 +27,7 @@ async function href(url, path) { } /** - * Error handler. + * Callback invoked upon failing to resolve a resource. * * @private * @param {Error} error - error object From 52aa78da1106c294d6e3ee8de4eed98460467e93 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:35:42 -0700 Subject: [PATCH 416/551] Update function docs --- spec/_static/javascripts/version_dropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index c66d51c65..1772a561d 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -65,6 +65,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * * @private * @param {Object} versions - versions object + * @returns {Promise} promise which resolves upon processing version data */ async function onDone(versions) { const currentURL = window.location.href; From 6649c2013a31f8cbc6c80e5968a1f218b8de874d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:40:11 -0700 Subject: [PATCH 417/551] Add debug statement --- spec/_static/javascripts/version_dropdown.js | 1 + 1 file changed, 1 insertion(+) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 1772a561d..645879283 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -68,6 +68,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @returns {Promise} promise which resolves upon processing version data */ async function onDone(versions) { + console.log(versions) const currentURL = window.location.href; let path = currentURL.split(/_site|array_api/)[1]; if (path) { From 3b32fe216021ab85f32ee9a54f102f9794d78d74 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:54:50 -0700 Subject: [PATCH 418/551] Add comments --- spec/_static/javascripts/version_dropdown.js | 29 ++++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 645879283..a3d81751b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -6,12 +6,12 @@ * @param {string} path - resource path * @returns {Promise} promise which resolves a resource URL */ -async function href(url, path) { +function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: - await fetch(url).then(onResponse).catch(onError); + return fetch(url).then(onResponse).catch(onError); /** * Callback invoked upon successfully resolving a resource. @@ -68,9 +68,15 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @returns {Promise} promise which resolves upon processing version data */ async function onDone(versions) { - console.log(versions) + console.log(versions); + + // Resolve the current browser URL: const currentURL = window.location.href; + + // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): let path = currentURL.split(/_site|array_api/)[1]; + + // Extract the resource subpath: if (path) { path = path.split("/"); path = path.slice(2, path.length); @@ -78,15 +84,28 @@ async function add_version_dropdown(json_loc, target_loc, text) { } else { path = ""; } + // For each version, create an anchor element and attempt to resolve a given resource for that version... + const promises = []; + const el = []; for (let key in versions) { if (versions.hasOwnProperty(key)) { let a = document.createElement("a"); a.innerHTML = key; a.title = key; - a.href = await href(target_loc + versions[key], path); - content.appendChild(a); + el.push(a); + promises.push(href(target_loc + versions[key], path)); } } + // Resolve all resource URLs: + const urls = await Promise.all(promises); + + // Append the version links to the dropdown menu: + for (let i = 0; i < urls.length; i++) { + let a = el[i]; + a.href = urls[i]; + content.appendChild(a); + } + // Set the button text: button.innerHTML = text; } From 74a2b1ac1a990d8390f04a7a212e77e4e5238bcf Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 16:55:55 -0700 Subject: [PATCH 419/551] Fix function description --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a3d81751b..6145549fc 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -1,5 +1,5 @@ /** -* Returns a URL corresponding to a versioned resource (if one exists). +* Returns a promise for resolving a URL corresponding to a versioned resource (if one exists). * * @private * @param {string} url - base URL From a8a3e51302b5243a85ce6c38b3b19269156c336d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:08:01 -0700 Subject: [PATCH 420/551] Add debug statements --- spec/_static/javascripts/version_dropdown.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 6145549fc..547df387a 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -58,7 +58,11 @@ async function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(button); dropdown.appendChild(content); - await $.getJSON(json_loc).done(onDone).fail(onFail).always(onAlways); + const p = $.getJSON(json_loc); + console.log(p); + + p.done(onDone).fail(onFail).always(onAlways); + await p; /** * Callback invoked upon resolving a JSON resource. @@ -115,6 +119,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @private */ function onFail() { + console.log("Failure"); button.innerHTML = "Other Versions Not Found"; } @@ -124,6 +129,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @private */ function onAlways() { + console.log("Always"); $(".navheader").append(dropdown); } }; From 02e31b4e3da96b6e83b485db54d170960dd7a809 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:15:58 -0700 Subject: [PATCH 421/551] Replace `done` with `then` --- spec/_static/javascripts/version_dropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 547df387a..cf290d24a 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -60,8 +60,8 @@ async function add_version_dropdown(json_loc, target_loc, text) { const p = $.getJSON(json_loc); console.log(p); - - p.done(onDone).fail(onFail).always(onAlways); + + p.then(onVersions).fail(onFail).always(onAlways); await p; /** @@ -71,7 +71,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @param {Object} versions - versions object * @returns {Promise} promise which resolves upon processing version data */ - async function onDone(versions) { + async function onVersions(versions) { console.log(versions); // Resolve the current browser URL: From 05435222a7cc584c8682bf0df7b4abc3c081eb3a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:24:23 -0700 Subject: [PATCH 422/551] Rearrange callback assignments --- spec/_static/javascripts/version_dropdown.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index cf290d24a..8f1e170cc 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -61,8 +61,9 @@ async function add_version_dropdown(json_loc, target_loc, text) { const p = $.getJSON(json_loc); console.log(p); - p.then(onVersions).fail(onFail).always(onAlways); - await p; + p.fail(onFail).always(onAlways); + + await p.then(onVersions); /** * Callback invoked upon resolving a JSON resource. @@ -119,7 +120,6 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @private */ function onFail() { - console.log("Failure"); button.innerHTML = "Other Versions Not Found"; } From 281d236fc2a0dad068dc99bd9e271b0930ec164a Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:34:40 -0700 Subject: [PATCH 423/551] Invoke `promise` method to return a deferred object's promise --- spec/_static/javascripts/version_dropdown.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 8f1e170cc..d5f85d1e5 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -61,9 +61,10 @@ async function add_version_dropdown(json_loc, target_loc, text) { const p = $.getJSON(json_loc); console.log(p); + p.then(onVersions); p.fail(onFail).always(onAlways); - await p.then(onVersions); + await p.promise(); /** * Callback invoked upon resolving a JSON resource. From 3350625bdcc27873da733067130bc9732bc9cb10 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:49:22 -0700 Subject: [PATCH 424/551] Refactor to use `fetch` --- spec/_static/javascripts/version_dropdown.js | 33 +++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d5f85d1e5..d6083b018 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -58,13 +58,20 @@ async function add_version_dropdown(json_loc, target_loc, text) { dropdown.appendChild(button); dropdown.appendChild(content); - const p = $.getJSON(json_loc); - console.log(p); + const opts = { + 'method': 'GET' + }; + await fetch(json_loc, opts).then(onResponse).then(onVersions).catch(onError); - p.then(onVersions); - p.fail(onFail).always(onAlways); - - await p.promise(); + /** + * Callback invoked upon resolving a resource. + * + * @private + * @param {Object} response - response object + */ + function onResponse(response) { + return response.json(); + } /** * Callback invoked upon resolving a JSON resource. @@ -113,24 +120,20 @@ async function add_version_dropdown(json_loc, target_loc, text) { } // Set the button text: button.innerHTML = text; + + // Append dropdown: + $(".navheader").append(dropdown); } /** - * Callback invoked upon failing to resolve a JSON resource. + * Callback invoked upon failing to resolve a resource. * * @private */ function onFail() { button.innerHTML = "Other Versions Not Found"; - } - /** - * Callback which is always invoked upon attempting to resolve a JSON resource. - * - * @private - */ - function onAlways() { - console.log("Always"); + // Append dropdown: $(".navheader").append(dropdown); } }; From 1c32d2e363a573322b441a969018872ef96ba2f1 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 17:50:06 -0700 Subject: [PATCH 425/551] Fix function name --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index d6083b018..4b0e79501 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -130,7 +130,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { * * @private */ - function onFail() { + function onError() { button.innerHTML = "Other Versions Not Found"; // Append dropdown: From 6c3068f77cc304bc84cd384ea6bdca8251e122ff Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:34:03 -0700 Subject: [PATCH 426/551] Fix regular expression --- spec/_static/javascripts/version_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index 4b0e79501..f9e5b2cfd 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -87,7 +87,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { const currentURL = window.location.href; // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): - let path = currentURL.split(/_site|array_api/)[1]; + let path = currentURL.split(/_site|array\-api/)[1]; // Extract the resource subpath: if (path) { From 48d926f3017d9614e4458e7e94d64d00c4c08ca8 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:37:17 -0700 Subject: [PATCH 427/551] Add debug statements --- spec/_static/javascripts/version_dropdown.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index f9e5b2cfd..a462ec93f 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -9,7 +9,7 @@ function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; - +console.log(url); // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: return fetch(url).then(onResponse).catch(onError); @@ -81,14 +81,12 @@ async function add_version_dropdown(json_loc, target_loc, text) { * @returns {Promise} promise which resolves upon processing version data */ async function onVersions(versions) { - console.log(versions); - // Resolve the current browser URL: const currentURL = window.location.href; // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): let path = currentURL.split(/_site|array\-api/)[1]; - +console.log(path); // Extract the resource subpath: if (path) { path = path.split("/"); From 01e433ae653cff2da80518ee138beca274025112 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:45:49 -0700 Subject: [PATCH 428/551] Remove debug statements --- spec/_static/javascripts/version_dropdown.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a462ec93f..a7a859f6b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -9,7 +9,7 @@ function href(url, path) { const defaultURL = url + "/index.html"; url += "/" + path; -console.log(url); + // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: return fetch(url).then(onResponse).catch(onError); @@ -86,7 +86,7 @@ async function add_version_dropdown(json_loc, target_loc, text) { // Check whether the user is currently on a resource page (e.g., is viewing the specification for a particular function): let path = currentURL.split(/_site|array\-api/)[1]; -console.log(path); + // Extract the resource subpath: if (path) { path = path.split("/"); From 4448b37741058d2c4c01e4056e775abdb7ab1637 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Sat, 8 Jul 2023 19:51:57 -0700 Subject: [PATCH 429/551] Perform head request rather than request entire resource --- spec/_static/javascripts/version_dropdown.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/spec/_static/javascripts/version_dropdown.js b/spec/_static/javascripts/version_dropdown.js index a7a859f6b..4d7b7378b 100644 --- a/spec/_static/javascripts/version_dropdown.js +++ b/spec/_static/javascripts/version_dropdown.js @@ -11,7 +11,10 @@ function href(url, path) { url += "/" + path; // If a versioned resource exists, return the resource's URL; otherwise, return a default URL: - return fetch(url).then(onResponse).catch(onError); + const opts = { + 'method': 'HEAD' + }; + return fetch(url, opts).then(onResponse).catch(onError); /** * Callback invoked upon successfully resolving a resource. From 2056a94c6571d7c9ef15298d308b28fead1471dd Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 10 Jul 2023 07:57:41 -0700 Subject: [PATCH 430/551] Fix optional keyword argument in `take` signature (#644) This commit fixes the function signature for `take`. Namely, when an input array is one-dimensional, the `axis` kwarg is optional; when the array has more than one dimension, the `axis` kwarg is required. Unfortunately, the type signature cannot encode this duality, and we must rely on the specification text to clarify that the `axis` kwarg is required for arrays having ranks greater than unity. Ref: https://github.com/data-apis/array-api-compat/issues/34 --- src/array_api_stubs/_2022_12/indexing_functions.py | 4 ++-- src/array_api_stubs/_draft/indexing_functions.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/indexing_functions.py b/src/array_api_stubs/_2022_12/indexing_functions.py index e76ce7484..0cbad55ab 100644 --- a/src/array_api_stubs/_2022_12/indexing_functions.py +++ b/src/array_api_stubs/_2022_12/indexing_functions.py @@ -1,7 +1,7 @@ -from ._types import Union, array +from ._types import Union, Optional, array -def take(x: array, indices: array, /, *, axis: int) -> array: +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: """ Returns elements of an array along an axis. diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index d57dc91e5..3b218fdac 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -1,7 +1,7 @@ -from ._types import Union, array +from ._types import Union, Optional, array -def take(x: array, indices: array, /, *, axis: int) -> array: +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: """ Returns elements of an array along an axis. From bd1e695db7cbfc11b1d31bc4dd33171d7a83f035 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Thu, 13 Jul 2023 09:48:24 -0700 Subject: [PATCH 431/551] Add specification for moving array axes to new positions --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index fc0e752b9..7eb7fa8b0 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -23,6 +23,7 @@ Objects in API concat expand_dims flip + moveaxis permute_dims reshape roll diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index d62cd4f07..f71a75517 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -99,6 +99,26 @@ def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> """ +def moveaxis(x: array, source: Union[int, Tuple[int, ...]], destination: Union[int, Tuple[int, ...]], /) -> array: + """ + Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. + + Parameters + ---------- + x: array + input array. + source: Union[int, Tuple[int, ...]] + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + destination: Union[int, Tuple[int, ...]] + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + + Returns + ------- + out: array + an array containing reordered axes. The returned array must have the same data type as ``x``. + """ + + def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: """ Permutes the axes (dimensions) of an array ``x``. @@ -240,6 +260,7 @@ def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: "concat", "expand_dims", "flip", + "moveaxis", "permute_dims", "reshape", "roll", From 6a2dea289ec7d290c76a7fc03451105ab38831df Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Sat, 15 Jul 2023 14:50:41 -0500 Subject: [PATCH 432/551] Fix documentation for constants Sphinx cannot find the docstring corresponding to a constant unless you point it to the exact file where it is, since it doesn't actually live on the object itself. See https://github.com/sphinx-doc/sphinx/issues/6495 Fixes #601 --- spec/2021.12/API_specification/constants.rst | 2 +- spec/2022.12/API_specification/constants.rst | 2 +- spec/draft/API_specification/constants.rst | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/2021.12/API_specification/constants.rst b/spec/2021.12/API_specification/constants.rst index abe256533..71cb8688d 100644 --- a/spec/2021.12/API_specification/constants.rst +++ b/spec/2021.12/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: array_api +.. currentmodule:: array_api.constants .. NOTE: please keep the functions in alphabetical order diff --git a/spec/2022.12/API_specification/constants.rst b/spec/2022.12/API_specification/constants.rst index abe256533..71cb8688d 100644 --- a/spec/2022.12/API_specification/constants.rst +++ b/spec/2022.12/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: array_api +.. currentmodule:: array_api.constants .. NOTE: please keep the functions in alphabetical order diff --git a/spec/draft/API_specification/constants.rst b/spec/draft/API_specification/constants.rst index abe256533..71cb8688d 100644 --- a/spec/draft/API_specification/constants.rst +++ b/spec/draft/API_specification/constants.rst @@ -10,7 +10,7 @@ A conforming implementation of the array API standard must provide and support t Objects in API -------------- -.. currentmodule:: array_api +.. currentmodule:: array_api.constants .. NOTE: please keep the functions in alphabetical order From 91c6163e8e24be9e98549a5681669ea97705de07 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 19 Jul 2023 13:33:51 -0500 Subject: [PATCH 433/551] Add custom css to avoid line-through decorations in Literal arguments --- spec/_static/css/custom.css | 3 +++ src/_array_api_conf.py | 1 + 2 files changed, 4 insertions(+) create mode 100644 spec/_static/css/custom.css diff --git a/spec/_static/css/custom.css b/spec/_static/css/custom.css new file mode 100644 index 000000000..35506ee5f --- /dev/null +++ b/spec/_static/css/custom.css @@ -0,0 +1,3 @@ +s { + text-decoration: inherit; +} \ No newline at end of file diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 490d3a2aa..e183082ec 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -211,3 +211,4 @@ def process_signature(app, what, name, obj, options, signature, return_annotatio def setup(app): app.connect("autodoc-process-signature", process_signature) + app.add_css_file('css/custom.css') From b08480f9dddca4f3a1cb4423424a12f0659b256d Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 19 Jul 2023 13:54:07 -0500 Subject: [PATCH 434/551] fix invalid latex in qr function API docstring --- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index c1ff64c3e..e0552f17a 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -473,7 +473,7 @@ def qr( where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. - The reduced QR decomposition equals with the complete QR decomposition when :math:`n \qeq m` (wide matrix). + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index b03f6eb63..3cec1770e 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -473,7 +473,7 @@ def qr( where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. - The reduced QR decomposition equals with the complete QR decomposition when :math:`n \qeq m` (wide matrix). + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. From b551155cb10f48dab6f45611395c28b18e16cd15 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 19 Jul 2023 15:56:18 -0700 Subject: [PATCH 435/551] Set Circle CI API token --- .github/workflows/preview.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/preview.yml b/.github/workflows/preview.yml index 347dbfb8d..43d8c0b68 100644 --- a/.github/workflows/preview.yml +++ b/.github/workflows/preview.yml @@ -11,6 +11,7 @@ jobs: uses: larsoner/circleci-artifacts-redirector-action@master with: repo-token: ${{ secrets.GITHUB_TOKEN }} + api-token: ${{ secrets.CIRCLECI_TOKEN }} artifact-path: 0/_site/draft/index.html circleci-jobs: build_page job-title: Check the rendered docs here! From e72b3ca08cd7427f04f3f2093d832bf6c90c4a96 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Thu, 20 Jul 2023 04:18:15 -0500 Subject: [PATCH 436/551] Add version to the nav title (#662) --- spec/2021.12/conf.py | 4 ++++ spec/2022.12/conf.py | 3 +++ spec/draft/conf.py | 3 +++ 3 files changed, 10 insertions(+) diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index 04af8974d..cfbc80b25 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -6,4 +6,8 @@ from _array_api_conf import * release = "2021.12" + +nav_title = html_theme_options.get("nav_title") + " v{}".format(release) +html_theme_options.update({"nav_title": nav_title}) + sys.modules["array_api"] = stubs_mod diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py index fd05b644e..1831a0387 100644 --- a/spec/2022.12/conf.py +++ b/spec/2022.12/conf.py @@ -6,4 +6,7 @@ from _array_api_conf import * release = "2022.12" + +nav_title = html_theme_options.get("nav_title") + " v{}".format(release) +html_theme_options.update({"nav_title": nav_title}) sys.modules["array_api"] = stubs_mod diff --git a/spec/draft/conf.py b/spec/draft/conf.py index 4a57229b2..a93585fef 100644 --- a/spec/draft/conf.py +++ b/spec/draft/conf.py @@ -6,4 +6,7 @@ from _array_api_conf import * release = "DRAFT" + +nav_title = html_theme_options.get("nav_title") + " {}".format(release) +html_theme_options.update({"nav_title": nav_title}) sys.modules["array_api"] = stubs_mod From 825cec75215c179431f3eb2e733d836115bf237a Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 26 Jul 2023 13:17:30 -0500 Subject: [PATCH 437/551] add device kwarg to astype API --- .../_draft/data_type_functions.py | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 700bffd90..857d82ab8 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -1,7 +1,19 @@ -from ._types import Union, Tuple, array, dtype, finfo_object, iinfo_object - - -def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: +from ._types import ( + Union, + Tuple, + array, + dtype, + finfo_object, + iinfo_object, + device, + Optional +) + + +def astype( + x: array, dtype: dtype, /, *, copy: bool = True, + device: Optional[device] = None +) -> array: """ Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. @@ -31,6 +43,8 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: desired data type. copy: bool specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + device: Optional[device] + device on which to place the created array. Default: ``None``. Returns ------- From 1d99f906adde4fe96d49338c6dbd713aa526e0b8 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Date: Wed, 26 Jul 2023 17:19:00 -0500 Subject: [PATCH 438/551] clarify behavior when dtype=None in sum, prod and trace --- src/array_api_stubs/_draft/linalg.py | 9 +++++---- .../_draft/statistical_functions.py | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 3cec1770e..93711b13a 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -718,10 +718,11 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 93faaf31e..066da0da5 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -143,10 +143,11 @@ def prod( data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product. Default: ``None``. @@ -240,10 +241,11 @@ def sum( data type of the returned array. If ``None``, - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. From caca863cc228d14aa0a990084aaaf7a5a06175d9 Mon Sep 17 00:00:00 2001 From: Stephannie Jimenez Gacha Date: Thu, 27 Jul 2023 16:32:13 -0500 Subject: [PATCH 439/551] Add review changes Co-authored-by: Athan --- src/array_api_stubs/_draft/data_type_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 857d82ab8..726e6c8c4 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -44,7 +44,7 @@ def astype( copy: bool specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. device: Optional[device] - device on which to place the created array. Default: ``None``. + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. Returns ------- From 0fbbd5003d87849a6a0df73e7dc28cbe9f9acd60 Mon Sep 17 00:00:00 2001 From: Saul Shanabrook Date: Wed, 9 Aug 2023 13:11:54 -0400 Subject: [PATCH 440/551] Clarify types to allow None in indexing I believe that the indexing specification allow `None` in a selection tuple, but the current typing does not specify this. I have changed the signature for `__getitem__` but did not change `__setitem__`. I am not sure where it is documented if the indexing specification applies to both equally. --- src/array_api_stubs/_draft/array_object.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index cf6adcf3c..264f3a7b2 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -477,7 +477,7 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array ], /, ) -> array: @@ -488,7 +488,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns From 520d30cf04c96556f8589250c7f5c8479bd194c9 Mon Sep 17 00:00:00 2001 From: Lucas Colley <51488791+lucascolley@users.noreply.github.com> Date: Sat, 19 Aug 2023 00:58:40 +0100 Subject: [PATCH 441/551] Correct upper Cholesky description formula --- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index e0552f17a..a2207bb4c 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -18,7 +18,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: The upper Cholesky decomposition is defined similarly .. math:: - x = UU^{H} \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} where :math:`U` is an upper triangular matrix. diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 3cec1770e..29dd6849f 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -18,7 +18,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: The upper Cholesky decomposition is defined similarly .. math:: - x = UU^{H} \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} where :math:`U` is an upper triangular matrix. From caf1011e7b8254c2cb75d31dcfb31164eef5e39a Mon Sep 17 00:00:00 2001 From: Aaron Siddhartha Mondal Date: Thu, 7 Sep 2023 16:52:51 +0200 Subject: [PATCH 442/551] Use parameter name obj in asarray device doc (#681) The asarray creation function uses obj instead of x. --- src/array_api_stubs/_2021_12/creation_functions.py | 2 +- src/array_api_stubs/_2022_12/creation_functions.py | 2 +- src/array_api_stubs/_draft/creation_functions.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index 4ee683cd9..abfb38455 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -60,7 +60,7 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. device: Optional[device] - device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py index 8736efc29..42d6f9420 100644 --- a/src/array_api_stubs/_2022_12/creation_functions.py +++ b/src/array_api_stubs/_2022_12/creation_functions.py @@ -89,7 +89,7 @@ def asarray( If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. device: Optional[device] - device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 8736efc29..42d6f9420 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -89,7 +89,7 @@ def asarray( If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. device: Optional[device] - device on which to place the created array. If ``device`` is ``None`` and ``x`` is an array, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. From ba80d0aa194082bf23eb44dab4d3688b94943537 Mon Sep 17 00:00:00 2001 From: Nathaniel Starkman Date: Tue, 12 Sep 2023 04:01:37 -0400 Subject: [PATCH 443/551] Move `__all__` to PEP-8 recommended location (#683) Module level "dunders" (i.e. names with two leading and two trailing underscores) such as __all__, __author__, __version__, etc. should be placed after the module docstring but before any import statements except from __future__ imports. Python mandates that future-imports must appear in the module before any other code except docstrings. Signed-off-by: nstarman --- src/array_api_stubs/__init__.py | 1 - src/array_api_stubs/_draft/_types.py | 47 ++++--- src/array_api_stubs/_draft/array_object.py | 4 +- src/array_api_stubs/_draft/constants.py | 4 +- .../_draft/creation_functions.py | 40 +++--- .../_draft/data_type_functions.py | 6 +- src/array_api_stubs/_draft/data_types.py | 6 +- .../_draft/elementwise_functions.py | 126 +++++++++--------- src/array_api_stubs/_draft/fft.py | 35 +++-- .../_draft/indexing_functions.py | 5 +- src/array_api_stubs/_draft/linalg.py | 54 ++++---- .../_draft/linear_algebra_functions.py | 6 +- .../_draft/manipulation_functions.py | 30 ++--- .../_draft/searching_functions.py | 6 +- src/array_api_stubs/_draft/set_functions.py | 6 +- .../_draft/sorting_functions.py | 6 +- .../_draft/statistical_functions.py | 6 +- .../_draft/utility_functions.py | 6 +- 18 files changed, 197 insertions(+), 197 deletions(-) diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index b3c7f1976..4ac3783ef 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1,2 +1 @@ from . import _2021_12, _2022_12, _draft - diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 589606784..2a73dda24 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -6,6 +6,27 @@ """ from __future__ import annotations +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", +] + from dataclasses import dataclass from typing import ( Any, @@ -34,6 +55,7 @@ @dataclass class finfo_object: """Dataclass returned by `finfo`.""" + bits: int eps: float max: float @@ -41,14 +63,17 @@ class finfo_object: smallest_normal: float dtype: dtype + @dataclass class iinfo_object: """Dataclass returned by `iinfo`.""" + bits: int max: int min: int dtype: dtype + _T_co = TypeVar("_T_co", covariant=True) @@ -58,25 +83,3 @@ def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: def __len__(self, /) -> int: ... - - -__all__ = [ - "Any", - "List", - "Literal", - "NestedSequence", - "Optional", - "PyCapsule", - "SupportsBufferProtocol", - "SupportsDLPack", - "Tuple", - "Union", - "Sequence", - "array", - "device", - "dtype", - "ellipsis", - "finfo_object", - "iinfo_object", - "Enum", -] diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index cf6adcf3c..e5d34248c 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -1,5 +1,7 @@ from __future__ import annotations +__all__ = ["array"] + from ._types import ( array, dtype as Dtype, @@ -1059,5 +1061,3 @@ def to_device( array = _array - -__all__ = ["array"] diff --git a/src/array_api_stubs/_draft/constants.py b/src/array_api_stubs/_draft/constants.py index c7aaddc5e..c5735d09f 100644 --- a/src/array_api_stubs/_draft/constants.py +++ b/src/array_api_stubs/_draft/constants.py @@ -1,3 +1,5 @@ +__all__ = ["e", "inf", "nan", "newaxis", "pi"] + e = 2.718281828459045 """ IEEE 754 floating-point representation of Euler's constant. @@ -26,5 +28,3 @@ ``pi = 3.1415926535897932384626433...`` """ - -__all__ = ["e", "inf", "nan", "newaxis", "pi"] diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 42d6f9420..5e2bb44e6 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -1,3 +1,23 @@ +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] + + from ._types import ( List, NestedSequence, @@ -563,23 +583,3 @@ def zeros_like( out: array an array having the same shape as ``x`` and filled with zeros. """ - - -__all__ = [ - "arange", - "asarray", - "empty", - "empty_like", - "eye", - "from_dlpack", - "full", - "full_like", - "linspace", - "meshgrid", - "ones", - "ones_like", - "tril", - "triu", - "zeros", - "zeros_like", -] diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 700bffd90..a5e9895b2 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -1,3 +1,6 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + + from ._types import Union, Tuple, array, dtype, finfo_object, iinfo_object @@ -208,6 +211,3 @@ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: out: dtype the dtype resulting from an operation involving the input arrays and dtypes. """ - - -__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] diff --git a/src/array_api_stubs/_draft/data_types.py b/src/array_api_stubs/_draft/data_types.py index 614807414..d15f4a9f7 100644 --- a/src/array_api_stubs/_draft/data_types.py +++ b/src/array_api_stubs/_draft/data_types.py @@ -1,3 +1,6 @@ +__all__ = ["__eq__"] + + from ._types import dtype @@ -17,6 +20,3 @@ def __eq__(self: dtype, other: dtype, /) -> bool: out: bool a boolean indicating whether the data type objects are equal. """ - - -__all__ = ["__eq__"] diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 5f474e7c8..147eff9cd 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -1,3 +1,66 @@ +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "conj", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "real", + "remainder", + "round", + "sign", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] + + from ._types import array @@ -2477,66 +2540,3 @@ def trunc(x: array, /) -> array: - If ``x_i`` is ``-0``, the result is ``-0``. - If ``x_i`` is ``NaN``, the result is ``NaN``. """ - - -__all__ = [ - "abs", - "acos", - "acosh", - "add", - "asin", - "asinh", - "atan", - "atan2", - "atanh", - "bitwise_and", - "bitwise_left_shift", - "bitwise_invert", - "bitwise_or", - "bitwise_right_shift", - "bitwise_xor", - "ceil", - "conj", - "cos", - "cosh", - "divide", - "equal", - "exp", - "expm1", - "floor", - "floor_divide", - "greater", - "greater_equal", - "imag", - "isfinite", - "isinf", - "isnan", - "less", - "less_equal", - "log", - "log1p", - "log2", - "log10", - "logaddexp", - "logical_and", - "logical_not", - "logical_or", - "logical_xor", - "multiply", - "negative", - "not_equal", - "positive", - "pow", - "real", - "remainder", - "round", - "sign", - "sin", - "sinh", - "square", - "sqrt", - "subtract", - "tan", - "tanh", - "trunc", -] diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 7979095fe..4a59392d5 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -1,3 +1,20 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + from ._types import Tuple, Union, Sequence, array, Optional, Literal, device @@ -651,21 +668,3 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: .. versionadded:: 2022.12 """ - - -__all__ = [ - "fft", - "ifft", - "fftn", - "ifftn", - "rfft", - "irfft", - "rfftn", - "irfftn", - "hfft", - "ihfft", - "fftfreq", - "rfftfreq", - "fftshift", - "ifftshift", -] diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 3b218fdac..3f4c25215 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -1,3 +1,5 @@ +__all__ = ["take"] + from ._types import Union, Optional, array @@ -29,6 +31,3 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. versionadded:: 2022.12 """ - - -__all__ = ["take"] diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 29dd6849f..dc74cd239 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -1,3 +1,30 @@ +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] + + from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype from .constants import inf @@ -822,30 +849,3 @@ def vector_norm( .. versionchanged:: 2022.12 Added complex data type support. """ - - -__all__ = [ - "cholesky", - "cross", - "det", - "diagonal", - "eigh", - "eigvalsh", - "inv", - "matmul", - "matrix_norm", - "matrix_power", - "matrix_rank", - "matrix_transpose", - "outer", - "pinv", - "qr", - "slogdet", - "solve", - "svd", - "svdvals", - "tensordot", - "trace", - "vecdot", - "vector_norm", -] diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index d9ac2437c..a6f84e392 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -1,3 +1,6 @@ +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] + + from ._types import Tuple, Union, Sequence, array @@ -155,6 +158,3 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. """ - - -__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index d62cd4f07..74b62a689 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -1,3 +1,18 @@ +__all__ = [ + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "permute_dims", + "reshape", + "roll", + "squeeze", + "stack", + "unstack", +] + + from ._types import List, Optional, Tuple, Union, array @@ -232,18 +247,3 @@ def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: out: Tuple[array, ...] tuple of slices along the given dimension. All the arrays have the same shape. """ - - -__all__ = [ - "broadcast_arrays", - "broadcast_to", - "concat", - "expand_dims", - "flip", - "permute_dims", - "reshape", - "roll", - "squeeze", - "stack", - "unstack", -] diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 9dcc0f95c..e586a7656 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -1,3 +1,6 @@ +__all__ = ["argmax", "argmin", "nonzero", "where"] + + from ._types import Optional, Tuple, array @@ -102,6 +105,3 @@ def where(condition: array, x1: array, x2: array, /) -> array: out: array an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. """ - - -__all__ = ["argmax", "argmin", "nonzero", "where"] diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 661d3df90..394fa2b17 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -1,3 +1,6 @@ +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] + + from ._types import Tuple, array @@ -166,6 +169,3 @@ def unique_values(x: array, /) -> array: .. versionchanged:: 2022.12 Added complex data type support. """ - - -__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] diff --git a/src/array_api_stubs/_draft/sorting_functions.py b/src/array_api_stubs/_draft/sorting_functions.py index 3eb52c8ce..2dc4ac410 100644 --- a/src/array_api_stubs/_draft/sorting_functions.py +++ b/src/array_api_stubs/_draft/sorting_functions.py @@ -1,3 +1,6 @@ +__all__ = ["argsort", "sort"] + + from ._types import array @@ -53,6 +56,3 @@ def sort( out : array a sorted array. The returned array must have the same data type and shape as ``x``. """ - - -__all__ = ["argsort", "sort"] diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 93faaf31e..7648f1c3f 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -1,3 +1,6 @@ +__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] + + from ._types import Optional, Tuple, Union, array, dtype @@ -315,6 +318,3 @@ def var( - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). """ - - -__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index 64e5de297..81d8dca41 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -1,3 +1,6 @@ +__all__ = ["all", "any"] + + from ._types import Optional, Tuple, Union, array @@ -81,6 +84,3 @@ def any( .. versionchanged:: 2022.12 Added complex data type support. """ - - -__all__ = ["all", "any"] From 2e0723844cc4b789f0ec86dc474d6cfa9387262e Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Tue, 12 Sep 2023 09:03:24 +0100 Subject: [PATCH 444/551] Add lucascolley to all contributors (#682) --- .all-contributorsrc | 10 ++++++++++ README.md | 5 ++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index f7f25e7d4..1e46cd5c1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -616,6 +616,16 @@ "contributions": [ "ideas" ] + }, + { + "login": "lucascolley", + "name": "Lucas Colley", + "avatar_url": "https://avatars.githubusercontent.com/u/51488791?v=4", + "profile": "https://github.com/lucascolley", + "contributions": [ + "maintenance", + "bug" + ] } ], "contributorsPerLine": 7 diff --git a/README.md b/README.md index dbfee4cea..4e72e269a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Array API standard -[![All Contributors](https://img.shields.io/badge/all_contributors-63-orange.svg?style=flat-square)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-64-orange.svg?style=flat-square)](#contributors-) This repository contains documents, tooling and other content related to the @@ -233,6 +233,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
Franck Charras
Franck Charras

🤔 Keith Kraus
Keith Kraus

🤔 + + Lucas Colley
Lucas Colley

🚧 🐛 + From 678f9eab5a593005e7bb80a46156c27b210cfcea Mon Sep 17 00:00:00 2001 From: Nathaniel Starkman Date: Fri, 15 Sep 2023 08:36:59 -0400 Subject: [PATCH 445/551] Add style checking with pre-commit + black, and a CI job (#684) Signed-off-by: nstarman --- .git-blame-ignore-revs | 2 +- .github/workflows/ci.yml | 46 ++++++ .github/workflows/pages.yml | 4 +- .pre-commit-config.yaml | 50 ++++++ CHANGELOG.md | 2 +- CODE_OF_CONDUCT.md | 2 +- README.md | 2 +- pyproject.toml | 3 + spec/2021.12/benchmark_suite.md | 2 +- spec/2021.12/conf.py | 1 + spec/2021.12/design_topics/accuracy.rst | 2 +- spec/2021.12/design_topics/parallelism.rst | 2 +- spec/2021.12/future_API_evolution.md | 2 +- spec/2021.12/usage_data.md | 4 +- spec/2021.12/use_cases.md | 2 +- spec/2022.12/benchmark_suite.md | 2 +- spec/2022.12/conf.py | 1 + spec/2022.12/design_topics/accuracy.rst | 2 +- .../2022.12/design_topics/complex_numbers.rst | 4 +- spec/2022.12/design_topics/parallelism.rst | 2 +- spec/2022.12/future_API_evolution.md | 2 +- spec/2022.12/usage_data.md | 4 +- spec/2022.12/use_cases.md | 2 +- spec/_static/css/custom.css | 2 +- spec/_templates/property.rst | 2 +- spec/draft/benchmark_suite.md | 2 +- spec/draft/conf.py | 1 + spec/draft/design_topics/accuracy.rst | 2 +- spec/draft/design_topics/complex_numbers.rst | 4 +- spec/draft/design_topics/parallelism.rst | 2 +- spec/draft/future_API_evolution.md | 2 +- spec/draft/usage_data.md | 4 +- spec/draft/use_cases.md | 2 +- src/_array_api_conf.py | 119 +++++++-------- src/array_api_stubs/_2021_12/_types.py | 59 ++++++-- src/array_api_stubs/_2021_12/array_object.py | 49 ++++-- src/array_api_stubs/_2021_12/constants.py | 6 +- .../_2021_12/creation_functions.py | 143 +++++++++++++++--- .../_2021_12/data_type_functions.py | 18 ++- src/array_api_stubs/_2021_12/data_types.py | 2 + .../_2021_12/elementwise_functions.py | 116 +++++++++++++- src/array_api_stubs/_2021_12/linalg.py | 79 +++++++++- .../_2021_12/linear_algebra_functions.py | 15 +- .../_2021_12/manipulation_functions.py | 36 ++++- .../_2021_12/searching_functions.py | 7 +- src/array_api_stubs/_2021_12/set_functions.py | 7 +- .../_2021_12/sorting_functions.py | 13 +- .../_2021_12/statistical_functions.py | 70 ++++++++- .../_2021_12/utility_functions.py | 21 ++- src/array_api_stubs/_2022_12/_types.py | 4 + 50 files changed, 767 insertions(+), 165 deletions(-) create mode 100644 .github/workflows/ci.yml create mode 100644 .pre-commit-config.yaml diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 64a94ebe7..4fd6df5d4 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -4,4 +4,4 @@ # Move special cases to notes sections 816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 0a2fa71a32b924cc92718db29910a6cbbc5e9341 -931144e7d7d5c8b23393aa730ef28962a35b113b \ No newline at end of file +931144e7d7d5c8b23393aa730ef28962a35b113b diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..6d3ba5c27 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +#/ +# @license MIT +# +# Copyright (c) 2022 Python Data APIs Consortium. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +#/ + +# Workflow name: +name: ci + +# Workflow triggers: +on: + pull_request: + push: + branches: [main,] + +# Workflow jobs: +jobs: + + main: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-python@v4 + with: + python-version: 3.8 + - uses: pre-commit/action@v3.0.0 + - uses: pre-commit-ci/lite-action@v1.0.1 + if: always() diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml index b328abc11..7576076ef 100644 --- a/.github/workflows/pages.yml +++ b/.github/workflows/pages.yml @@ -45,10 +45,10 @@ jobs: # Avoid running this workflow for forks and allow skipping CI: if: "github.repository == 'data-apis/array-api' && !contains(github.event.head_commit.message, '[ci skip]') && !contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[skip github]')" - + # Define a sequence of job steps... steps: - + # Checkout the repository: - name: 'Checkout repository' uses: actions/checkout@v2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 000000000..7ec7f02a8 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,50 @@ +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.4.0 + hooks: + - id: check-added-large-files + # Prevent giant files from being committed. + - id: check-ast + # Simply check whether files parse as valid python. + - id: check-case-conflict + # Check for files with names that would conflict on a case-insensitive + # filesystem like MacOS HFS+ or Windows FAT. + - id: check-json + # Attempts to load all json files to verify syntax. + - id: check-merge-conflict + # Check for files that contain merge conflict strings. + - id: check-symlinks + # Checks for symlinks which do not point to anything. + - id: check-toml + # Attempts to load all TOML files to verify syntax. + - id: check-xml + # Attempts to load all xml files to verify syntax. + - id: check-yaml + # Attempts to load all yaml files to verify syntax. + exclude: ".*(.github.*)$" + - id: debug-statements + # Check for debugger imports and py37+ breakpoint() calls in python + # source. + - id: detect-private-key + # Checks for the existence of private keys. + - id: end-of-file-fixer + # Makes sure files end in a newline and only a newline. + - id: trailing-whitespace + # Trims trailing whitespace. + exclude_types: [python] + + - repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: python-check-mock-methods + # Prevent common mistakes of assert mck.not_called(), assert + # mck.called_once_with(...) and mck.assert_called. + - id: text-unicode-replacement-char + # Forbid files which have a UTF-8 Unicode replacement character. + - id: python-check-blanket-noqa + # Enforce that all noqa annotations always occur with specific codes. + + - repo: https://github.com/psf/black-pre-commit-mirror + rev: 23.7.0 + hooks: + - id: black diff --git a/CHANGELOG.md b/CHANGELOG.md index 002d4fec9..0897e4ea5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -196,4 +196,4 @@ The following is a list of fixes and points of clarification with regard to the - `linspace`: conversion of `start` and `stop` should follow type promotion rules ([gh-568](https://github.com/data-apis/array-api/pull/568)) - `nonzero`: clarify that, for arrays having a boolean data type, non-zero elements are those elements which equal `True` ([gh-441](https://github.com/data-apis/array-api/pull/441)) - `trunc`: fix description ([gh-511](https://github.com/data-apis/array-api/pull/511)) -- `vecdot`: clarify broadcasting behavior ([gh-417](https://github.com/data-apis/array-api/pull/417) and [gh-473](https://github.com/data-apis/array-api/pull/473)) \ No newline at end of file +- `vecdot`: clarify broadcasting behavior ([gh-417](https://github.com/data-apis/array-api/pull/417) and [gh-473](https://github.com/data-apis/array-api/pull/473)) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 3ceb0ad58..9e9419abe 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,3 +1,3 @@ Please note that the Consortium for Python Data API Standards has a Code of Conduct that we ask everyone to respect, see: -https://github.com/data-apis/.github/blob/master/CODE_OF_CONDUCT.md \ No newline at end of file +https://github.com/data-apis/.github/blob/master/CODE_OF_CONDUCT.md diff --git a/README.md b/README.md index 4e72e269a..fef3099ff 100644 --- a/README.md +++ b/README.md @@ -244,4 +244,4 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! \ No newline at end of file +This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome! diff --git a/pyproject.toml b/pyproject.toml index b4f991c45..57af04207 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,3 +29,6 @@ doc = [ [build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" + +[tool.black] +line-length = 88 diff --git a/spec/2021.12/benchmark_suite.md b/spec/2021.12/benchmark_suite.md index da203cbf6..41066c6a4 100644 --- a/spec/2021.12/benchmark_suite.md +++ b/spec/2021.12/benchmark_suite.md @@ -1,3 +1,3 @@ # Benchmark suite -Adding a benchmark suite is planned in the future. \ No newline at end of file +Adding a benchmark suite is planned in the future. diff --git a/spec/2021.12/conf.py b/spec/2021.12/conf.py index cfbc80b25..9638670b4 100644 --- a/spec/2021.12/conf.py +++ b/spec/2021.12/conf.py @@ -1,5 +1,6 @@ import sys from pathlib import Path + sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2021_12 as stubs_mod diff --git a/spec/2021.12/design_topics/accuracy.rst b/spec/2021.12/design_topics/accuracy.rst index df417d546..8c97db698 100644 --- a/spec/2021.12/design_topics/accuracy.rst +++ b/spec/2021.12/design_topics/accuracy.rst @@ -74,4 +74,4 @@ This specification does not specify accuracy requirements for statistical functi Linear Algebra -------------- -This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2021.12/design_topics/parallelism.rst b/spec/2021.12/design_topics/parallelism.rst index 77d06c966..f013a9cf9 100644 --- a/spec/2021.12/design_topics/parallelism.rst +++ b/spec/2021.12/design_topics/parallelism.rst @@ -21,4 +21,4 @@ coordination of parallelization behavior in a stack of Python libraries are: Option (1) may possibly fit in a future version of this array API standard. `array-api issue 4 `_ contains -more detailed discussion on the topic of parallelism. \ No newline at end of file +more detailed discussion on the topic of parallelism. diff --git a/spec/2021.12/future_API_evolution.md b/spec/2021.12/future_API_evolution.md index 719b554e3..443f683d5 100644 --- a/spec/2021.12/future_API_evolution.md +++ b/spec/2021.12/future_API_evolution.md @@ -57,4 +57,4 @@ than Python package versioning. The frequency of releasing a new version of an API standard will likely be at regular intervals and on the order of one year, however no assumption on -frequency of new versions appearing must be made. \ No newline at end of file +frequency of new versions appearing must be made. diff --git a/spec/2021.12/usage_data.md b/spec/2021.12/usage_data.md index 7963333ff..c2dcd5d65 100644 --- a/spec/2021.12/usage_data.md +++ b/spec/2021.12/usage_data.md @@ -82,5 +82,5 @@ See the [`python-record-api`](https://github.com/data-apis/python-record-api) re Design and usage data support specification decision-making in the following ways. - Validate user stories to ensure that proposals satisfy existing needs. -- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). -- Inform technical design discussions to ensure that proposals are grounded in empirical data. \ No newline at end of file +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2021.12/use_cases.md b/spec/2021.12/use_cases.md index 50b6bd24d..26f7a529c 100644 --- a/spec/2021.12/use_cases.md +++ b/spec/2021.12/use_cases.md @@ -232,4 +232,4 @@ def check(x, y): # (this is different from Numpy, whose behaviour depends on # the *values* of the arguments -- see PyArray_CanCastArrayTo). self.assertEqual(got.dtype, x.dtype) -``` \ No newline at end of file +``` diff --git a/spec/2022.12/benchmark_suite.md b/spec/2022.12/benchmark_suite.md index da203cbf6..41066c6a4 100644 --- a/spec/2022.12/benchmark_suite.md +++ b/spec/2022.12/benchmark_suite.md @@ -1,3 +1,3 @@ # Benchmark suite -Adding a benchmark suite is planned in the future. \ No newline at end of file +Adding a benchmark suite is planned in the future. diff --git a/spec/2022.12/conf.py b/spec/2022.12/conf.py index 1831a0387..e056bb7f2 100644 --- a/spec/2022.12/conf.py +++ b/spec/2022.12/conf.py @@ -1,5 +1,6 @@ import sys from pathlib import Path + sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _2022_12 as stubs_mod diff --git a/spec/2022.12/design_topics/accuracy.rst b/spec/2022.12/design_topics/accuracy.rst index df417d546..8c97db698 100644 --- a/spec/2022.12/design_topics/accuracy.rst +++ b/spec/2022.12/design_topics/accuracy.rst @@ -74,4 +74,4 @@ This specification does not specify accuracy requirements for statistical functi Linear Algebra -------------- -This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2022.12/design_topics/complex_numbers.rst b/spec/2022.12/design_topics/complex_numbers.rst index da441499a..0eca79e91 100644 --- a/spec/2022.12/design_topics/complex_numbers.rst +++ b/spec/2022.12/design_topics/complex_numbers.rst @@ -27,7 +27,7 @@ Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer po In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. .. warning:: - All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. @@ -58,4 +58,4 @@ Valued-based Promotion According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. -By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. \ No newline at end of file +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/2022.12/design_topics/parallelism.rst b/spec/2022.12/design_topics/parallelism.rst index 77d06c966..f013a9cf9 100644 --- a/spec/2022.12/design_topics/parallelism.rst +++ b/spec/2022.12/design_topics/parallelism.rst @@ -21,4 +21,4 @@ coordination of parallelization behavior in a stack of Python libraries are: Option (1) may possibly fit in a future version of this array API standard. `array-api issue 4 `_ contains -more detailed discussion on the topic of parallelism. \ No newline at end of file +more detailed discussion on the topic of parallelism. diff --git a/spec/2022.12/future_API_evolution.md b/spec/2022.12/future_API_evolution.md index 719b554e3..443f683d5 100644 --- a/spec/2022.12/future_API_evolution.md +++ b/spec/2022.12/future_API_evolution.md @@ -57,4 +57,4 @@ than Python package versioning. The frequency of releasing a new version of an API standard will likely be at regular intervals and on the order of one year, however no assumption on -frequency of new versions appearing must be made. \ No newline at end of file +frequency of new versions appearing must be made. diff --git a/spec/2022.12/usage_data.md b/spec/2022.12/usage_data.md index 7963333ff..c2dcd5d65 100644 --- a/spec/2022.12/usage_data.md +++ b/spec/2022.12/usage_data.md @@ -82,5 +82,5 @@ See the [`python-record-api`](https://github.com/data-apis/python-record-api) re Design and usage data support specification decision-making in the following ways. - Validate user stories to ensure that proposals satisfy existing needs. -- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). -- Inform technical design discussions to ensure that proposals are grounded in empirical data. \ No newline at end of file +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2022.12/use_cases.md b/spec/2022.12/use_cases.md index 50b6bd24d..26f7a529c 100644 --- a/spec/2022.12/use_cases.md +++ b/spec/2022.12/use_cases.md @@ -232,4 +232,4 @@ def check(x, y): # (this is different from Numpy, whose behaviour depends on # the *values* of the arguments -- see PyArray_CanCastArrayTo). self.assertEqual(got.dtype, x.dtype) -``` \ No newline at end of file +``` diff --git a/spec/_static/css/custom.css b/spec/_static/css/custom.css index 35506ee5f..51c73f65c 100644 --- a/spec/_static/css/custom.css +++ b/spec/_static/css/custom.css @@ -1,3 +1,3 @@ s { text-decoration: inherit; -} \ No newline at end of file +} diff --git a/spec/_templates/property.rst b/spec/_templates/property.rst index baf31cea3..74062629f 100644 --- a/spec/_templates/property.rst +++ b/spec/_templates/property.rst @@ -2,4 +2,4 @@ {{ name.split('.')[-1] | underline }} -.. auto{{ objtype }}:: {{ objname }} \ No newline at end of file +.. auto{{ objtype }}:: {{ objname }} diff --git a/spec/draft/benchmark_suite.md b/spec/draft/benchmark_suite.md index da203cbf6..41066c6a4 100644 --- a/spec/draft/benchmark_suite.md +++ b/spec/draft/benchmark_suite.md @@ -1,3 +1,3 @@ # Benchmark suite -Adding a benchmark suite is planned in the future. \ No newline at end of file +Adding a benchmark suite is planned in the future. diff --git a/spec/draft/conf.py b/spec/draft/conf.py index a93585fef..d02568c35 100644 --- a/spec/draft/conf.py +++ b/spec/draft/conf.py @@ -1,5 +1,6 @@ import sys from pathlib import Path + sys.path.insert(0, str(Path(__file__).parents[2] / "src")) from array_api_stubs import _draft as stubs_mod diff --git a/spec/draft/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst index df417d546..8c97db698 100644 --- a/spec/draft/design_topics/accuracy.rst +++ b/spec/draft/design_topics/accuracy.rst @@ -74,4 +74,4 @@ This specification does not specify accuracy requirements for statistical functi Linear Algebra -------------- -This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. \ No newline at end of file +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/draft/design_topics/complex_numbers.rst b/spec/draft/design_topics/complex_numbers.rst index da441499a..0eca79e91 100644 --- a/spec/draft/design_topics/complex_numbers.rst +++ b/spec/draft/design_topics/complex_numbers.rst @@ -27,7 +27,7 @@ Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer po In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. .. warning:: - All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. @@ -58,4 +58,4 @@ Valued-based Promotion According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. -By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. \ No newline at end of file +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/draft/design_topics/parallelism.rst b/spec/draft/design_topics/parallelism.rst index 77d06c966..f013a9cf9 100644 --- a/spec/draft/design_topics/parallelism.rst +++ b/spec/draft/design_topics/parallelism.rst @@ -21,4 +21,4 @@ coordination of parallelization behavior in a stack of Python libraries are: Option (1) may possibly fit in a future version of this array API standard. `array-api issue 4 `_ contains -more detailed discussion on the topic of parallelism. \ No newline at end of file +more detailed discussion on the topic of parallelism. diff --git a/spec/draft/future_API_evolution.md b/spec/draft/future_API_evolution.md index 719b554e3..443f683d5 100644 --- a/spec/draft/future_API_evolution.md +++ b/spec/draft/future_API_evolution.md @@ -57,4 +57,4 @@ than Python package versioning. The frequency of releasing a new version of an API standard will likely be at regular intervals and on the order of one year, however no assumption on -frequency of new versions appearing must be made. \ No newline at end of file +frequency of new versions appearing must be made. diff --git a/spec/draft/usage_data.md b/spec/draft/usage_data.md index 7963333ff..c2dcd5d65 100644 --- a/spec/draft/usage_data.md +++ b/spec/draft/usage_data.md @@ -82,5 +82,5 @@ See the [`python-record-api`](https://github.com/data-apis/python-record-api) re Design and usage data support specification decision-making in the following ways. - Validate user stories to ensure that proposals satisfy existing needs. -- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). -- Inform technical design discussions to ensure that proposals are grounded in empirical data. \ No newline at end of file +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/draft/use_cases.md b/spec/draft/use_cases.md index 50b6bd24d..26f7a529c 100644 --- a/spec/draft/use_cases.md +++ b/spec/draft/use_cases.md @@ -232,4 +232,4 @@ def check(x, y): # (this is different from Numpy, whose behaviour depends on # the *values* of the arguments -- see PyArray_CanCastArrayTo). self.assertEqual(got.dtype, x.dtype) -``` \ No newline at end of file +``` diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index e183082ec..d3a136eaa 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -16,9 +16,9 @@ # -- Project information ----------------------------------------------------- -project = 'Python array API standard' -copyright = '2020-2022, Consortium for Python Data API Standards' -author = 'Consortium for Python Data API Standards' +project = "Python array API standard" +copyright = "2020-2022, Consortium for Python Data API Standards" +author = "Consortium for Python Data API Standards" # -- General configuration --------------------------------------------------- @@ -26,23 +26,23 @@ # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ - 'myst_parser', - 'sphinx.ext.extlinks', - 'sphinx.ext.intersphinx', - 'sphinx.ext.todo', - 'sphinx.ext.autosummary', - 'sphinx.ext.napoleon', - 'sphinx.ext.autodoc', - 'sphinx_copybutton', - 'sphinx_favicon', - 'sphinx_markdown_tables', + "myst_parser", + "sphinx.ext.extlinks", + "sphinx.ext.intersphinx", + "sphinx.ext.todo", + "sphinx.ext.autosummary", + "sphinx.ext.napoleon", + "sphinx.ext.autodoc", + "sphinx_copybutton", + "sphinx_favicon", + "sphinx_markdown_tables", ] autosummary_generate = True -autodoc_typehints = 'signature' +autodoc_typehints = "signature" add_module_names = False -napoleon_custom_sections = [('Returns', 'params_style')] -default_role = 'code' +napoleon_custom_sections = [("Returns", "params_style")] +default_role = "code" # nitpicky = True makes Sphinx warn whenever a cross-reference target can't be # found. @@ -50,30 +50,33 @@ # autodoc wants to make cross-references for every type hint. But a lot of # them don't actually refer to anything that we have a document for. nitpick_ignore = [ - ('py:class', 'collections.abc.Sequence'), - ('py:class', "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:class', "Union[int, float, Literal[inf, - inf]]"), - ('py:obj', "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]"), - ('py:obj', "typing.Union[int, float, typing.Literal[inf, - inf]]"), - ('py:class', 'enum.Enum'), - ('py:class', 'ellipsis'), + ("py:class", "collections.abc.Sequence"), + ("py:class", "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), + ("py:class", "Union[int, float, Literal[inf, - inf]]"), + ( + "py:obj", + "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]", + ), + ("py:obj", "typing.Union[int, float, typing.Literal[inf, - inf]]"), + ("py:class", "enum.Enum"), + ("py:class", "ellipsis"), ] nitpick_ignore_regex = [ - ('py:class', '.*array'), - ('py:class', '.*device'), - ('py:class', '.*dtype'), - ('py:class', '.*NestedSequence'), - ('py:class', '.*SupportsBufferProtocol'), - ('py:class', '.*PyCapsule'), - ('py:class', '.*finfo_object'), - ('py:class', '.*iinfo_object'), + ("py:class", ".*array"), + ("py:class", ".*device"), + ("py:class", ".*dtype"), + ("py:class", ".*NestedSequence"), + ("py:class", ".*SupportsBufferProtocol"), + ("py:class", ".*PyCapsule"), + ("py:class", ".*finfo_object"), + ("py:class", ".*iinfo_object"), ] # In array_object.py we have to use aliased names for some types because they # would otherwise refer back to method objects of array autodoc_type_aliases = { - 'array': 'array', - 'Device': 'device', - 'Dtype': 'dtype', + "array": "array", + "Device": "device", + "Dtype": "dtype", } # Make autosummary show the signatures of functions in the tables using actual @@ -81,18 +84,19 @@ # just patch out the function that processes the signatures. See # https://github.com/sphinx-doc/sphinx/issues/10053. import sphinx.ext.autosummary as autosummary_mod -if hasattr(autosummary_mod, '_module'): + +if hasattr(autosummary_mod, "_module"): # It's a sphinx deprecated module wrapper object autosummary_mod = autosummary_mod._module autosummary_mod.mangle_signature = lambda sig, max_chars=30: sig # Add any paths that contain templates here, relative to this directory. -templates_path = ['../_templates'] +templates_path = ["../_templates"] # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. # This pattern also affects html_static_path and html_extra_path. -exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] +exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] # MyST options myst_heading_anchors = 3 @@ -106,12 +110,12 @@ extensions.append("sphinx_material") html_theme_path = sphinx_material.html_theme_path() html_context = sphinx_material.get_html_context() -html_theme = 'sphinx_material' +html_theme = "sphinx_material" # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['../_static'] +html_static_path = ["../_static"] # -- Material theme options (see theme.conf for more information) ------------ @@ -121,26 +125,20 @@ } html_theme_options = { - # Set the name of the project to appear in the navigation. - 'nav_title': f'Python array API standard', - + "nav_title": f"Python array API standard", # Set you GA account ID to enable tracking #'google_analytics_account': 'UA-XXXXX', - # Specify a base_url used to generate sitemap.xml. If not # specified, then no sitemap will be built. #'base_url': 'https://project.github.io/project', - # Set the color and the accent color (see # https://material.io/design/color/the-color-system.html) - 'color_primary': 'indigo', - 'color_accent': 'green', - + "color_primary": "indigo", + "color_accent": "green", # Set the repo location to get a badge with stats #'repo_url': 'https://github.com/project/project/', #'repo_name': 'Project', - "html_minify": False, "html_prettify": False, "css_minify": True, @@ -149,14 +147,12 @@ "touch_icon": "images/apple-icon-152x152.png", "theme_color": "#2196f3", "master_doc": False, - # Visible levels of the global TOC; -1 means unlimited - 'globaltoc_depth': 2, + "globaltoc_depth": 2, # If False, expand all TOC entries - 'globaltoc_collapse': True, + "globaltoc_collapse": True, # If True, show hidden TOC entries - 'globaltoc_includehidden': True, - + "globaltoc_includehidden": True, "nav_links": [ {"href": "index", "internal": True, "title": "Array API standard"}, { @@ -167,9 +163,8 @@ ], "heroes": { "index": "A common API for array and tensor Python libraries", - #"customization": "Configuration options to personalize your site.", + # "customization": "Configuration options to personalize your site.", }, - "version_dropdown": True, "version_json": "../versions.json", "table_classes": ["plain"], @@ -179,11 +174,11 @@ todo_include_todos = True favicons = [ - { - "rel": "icon", - "sizes": "196x195", - "href": "images/favicon.png", - }, + { + "rel": "icon", + "sizes": "196x195", + "href": "images/favicon.png", + }, ] html_use_index = True @@ -202,6 +197,7 @@ # -- Prettify type hints ----------------------------------------------------- r_type_prefix = re.compile(r"array_api(?:_stubs\._[a-z0-9_]+)?\._types\.") + def process_signature(app, what, name, obj, options, signature, return_annotation): if signature: signature = re.sub(r_type_prefix, "", signature) @@ -209,6 +205,7 @@ def process_signature(app, what, name, obj, options, signature, return_annotatio return_annotation = re.sub(r_type_prefix, "", return_annotation) return signature, return_annotation + def setup(app): app.connect("autodoc-process-signature", process_signature) - app.add_css_file('css/custom.css') + app.add_css_file("css/custom.css") diff --git a/src/array_api_stubs/_2021_12/_types.py b/src/array_api_stubs/_2021_12/_types.py index b55e8fb25..be81b40ae 100644 --- a/src/array_api_stubs/_2021_12/_types.py +++ b/src/array_api_stubs/_2021_12/_types.py @@ -7,18 +7,29 @@ from __future__ import annotations from dataclasses import dataclass -from typing import Any, List, Literal, Optional, Sequence, Tuple, TypeVar, Union, Protocol +from typing import ( + Any, + List, + Literal, + Optional, + Sequence, + Tuple, + TypeVar, + Union, + Protocol, +) from enum import Enum -array = TypeVar('array') -device = TypeVar('device') -dtype = TypeVar('dtype') -SupportsDLPack = TypeVar('SupportsDLPack') -SupportsBufferProtocol = TypeVar('SupportsBufferProtocol') -PyCapsule = TypeVar('PyCapsule') +array = TypeVar("array") +device = TypeVar("device") +dtype = TypeVar("dtype") +SupportsDLPack = TypeVar("SupportsDLPack") +SupportsBufferProtocol = TypeVar("SupportsBufferProtocol") +PyCapsule = TypeVar("PyCapsule") # ellipsis cannot actually be imported from anywhere, so include a dummy here # to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 -ellipsis = TypeVar('ellipsis') +ellipsis = TypeVar("ellipsis") + @dataclass class finfo_object: @@ -28,6 +39,7 @@ class finfo_object: min: float smallest_normal: float + @dataclass class iinfo_object: bits: int @@ -37,11 +49,32 @@ class iinfo_object: _T_co = TypeVar("_T_co", covariant=True) + class NestedSequence(Protocol[_T_co]): - def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: ... - def __len__(self, /) -> int: ... + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: + ... + + def __len__(self, /) -> int: + ... -__all__ = ['Any', 'List', 'Literal', 'NestedSequence', 'Optional', -'PyCapsule', 'SupportsBufferProtocol', 'SupportsDLPack', 'Tuple', 'Union', 'Sequence', -'array', 'device', 'dtype', 'ellipsis', 'finfo_object', 'iinfo_object', 'Enum'] +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", +] diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index ac6890f71..9aa7119d0 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -1,9 +1,20 @@ from __future__ import annotations -from ._types import (array, dtype as Dtype, device as Device, Optional, Tuple, - Union, Any, PyCapsule, Enum, ellipsis) - -class _array(): +from ._types import ( + array, + dtype as Dtype, + device as Device, + Optional, + Tuple, + Union, + Any, + PyCapsule, + Enum, + ellipsis, +) + + +class _array: def __init__(self) -> None: """ Initialize the attributes for the array object class. @@ -205,7 +216,9 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ - def __array_namespace__(self: array, /, *, api_version: Optional[str] = None) -> Any: + def __array_namespace__( + self: array, /, *, api_version: Optional[str] = None + ) -> Any: """ Returns an object that has all the array API functions on it. @@ -237,7 +250,9 @@ def __bool__(self: array, /) -> bool: a Python ``bool`` object representing the single element of the array. """ - def __dlpack__(self: array, /, *, stream: Optional[Union[int, Any]] = None) -> PyCapsule: + def __dlpack__( + self: array, /, *, stream: Optional[Union[int, Any]] = None + ) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -435,7 +450,13 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. """ - def __getitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], /) -> array: + def __getitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + /, + ) -> array: """ Returns ``self[key]``. @@ -877,7 +898,14 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ - def __setitem__(self: array, key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array], value: Union[int, float, bool, array], /) -> None: + def __setitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + value: Union[int, float, bool, array], + /, + ) -> None: """ Sets ``self[key]`` to ``value``. @@ -995,7 +1023,9 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ - def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None) -> array: + def to_device( + self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None + ) -> array: """ Copy the array from the device on which it currently resides to the specified ``device``. @@ -1018,4 +1048,5 @@ def to_device(self: array, device: Device, /, *, stream: Optional[Union[int, Any If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. """ + array = _array diff --git a/src/array_api_stubs/_2021_12/constants.py b/src/array_api_stubs/_2021_12/constants.py index 18c8ac761..c7aaddc5e 100644 --- a/src/array_api_stubs/_2021_12/constants.py +++ b/src/array_api_stubs/_2021_12/constants.py @@ -5,12 +5,12 @@ ``e = 2.71828182845904523536028747135266249775724709369995...`` """ -inf = float('inf') +inf = float("inf") """ IEEE 754 floating-point representation of (positive) infinity. """ -nan = float('nan') +nan = float("nan") """ IEEE 754 floating-point representation of Not a Number (``NaN``). """ @@ -27,4 +27,4 @@ ``pi = 3.1415926535897932384626433...`` """ -__all__ = ['e', 'inf', 'nan', 'newaxis', 'pi'] +__all__ = ["e", "inf", "nan", "newaxis", "pi"] diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index abfb38455..c7659d0df 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -1,7 +1,25 @@ -from ._types import (List, NestedSequence, Optional, SupportsBufferProtocol, Tuple, Union, array, - device, dtype) - -def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None, step: Union[int, float] = 1, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: +from ._types import ( + List, + NestedSequence, + Optional, + SupportsBufferProtocol, + Tuple, + Union, + array, + device, + dtype, +) + + +def arange( + start: Union[int, float], + /, + stop: Optional[Union[int, float]] = None, + step: Union[int, float] = 1, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. @@ -28,7 +46,15 @@ def arange(start: Union[int, float], /, stop: Optional[Union[int, float]] = None a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. """ -def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], /, *, dtype: Optional[dtype] = None, device: Optional[device] = None, copy: Optional[bool] = None) -> array: + +def asarray( + obj: Union[array, bool, int, float, NestedSequence, SupportsBufferProtocol], + /, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: r""" Convert the input to an array. @@ -70,7 +96,13 @@ def asarray(obj: Union[array, bool, int, float, NestedSequence, SupportsBufferPr an array containing the data from ``obj``. """ -def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def empty( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns an uninitialized array having a specified `shape`. @@ -89,7 +121,10 @@ def empty(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, an array containing uninitialized data. """ -def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def empty_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns an uninitialized array with the same ``shape`` as an input array ``x``. @@ -108,7 +143,16 @@ def empty_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d an array having the same shape as ``x`` and containing uninitialized data. """ -def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def eye( + n_rows: int, + n_cols: Optional[int] = None, + /, + *, + k: int = 0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. @@ -131,6 +175,7 @@ def eye(n_rows: int, n_cols: Optional[int] = None, /, *, k: int = 0, dtype: Opti an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. """ + def from_dlpack(x: object, /) -> array: """ Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. @@ -151,7 +196,14 @@ def from_dlpack(x: object, /) -> array: The returned array may be either a copy or a view. See :ref:`data-interchange` for details. """ -def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def full( + shape: Union[int, Tuple[int, ...]], + fill_value: Union[int, float], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with ``fill_value``. @@ -176,7 +228,15 @@ def full(shape: Union[int, Tuple[int, ...]], fill_value: Union[int, float], *, d an array where every element is equal to ``fill_value``. """ -def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def full_like( + x: array, + /, + fill_value: Union[int, float], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. @@ -204,7 +264,17 @@ def full_like(x: array, /, fill_value: Union[int, float], *, dtype: Optional[dty an array having the same shape as ``x`` and where every element is equal to ``fill_value``. """ -def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, dtype: Optional[dtype] = None, device: Optional[device] = None, endpoint: bool = True) -> array: + +def linspace( + start: Union[int, float], + stop: Union[int, float], + /, + num: int, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + endpoint: bool = True, +) -> array: """ Returns evenly spaced numbers over a specified interval. @@ -240,7 +310,8 @@ def linspace(start: Union[int, float], stop: Union[int, float], /, num: int, *, As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. """ -def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: + +def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -266,7 +337,13 @@ def meshgrid(*arrays: array, indexing: str = 'xy') -> List[array]: Each returned array should have the same data type as the input arrays. """ -def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def ones( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with ones. @@ -285,7 +362,10 @@ def ones(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, d an array containing ones. """ -def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def ones_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. @@ -304,6 +384,7 @@ def ones_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[de an array having the same shape as ``x`` and filled with ones. """ + def tril(x: array, /, *, k: int = 0) -> array: """ Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. @@ -327,6 +408,7 @@ def tril(x: array, /, *, k: int = 0) -> array: an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. """ + def triu(x: array, /, *, k: int = 0) -> array: """ Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. @@ -350,7 +432,13 @@ def triu(x: array, /, *, k: int = 0) -> array: an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. """ -def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def zeros( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Returns a new array having a specified ``shape`` and filled with zeros. @@ -369,7 +457,10 @@ def zeros(shape: Union[int, Tuple[int, ...]], *, dtype: Optional[dtype] = None, an array containing zeros. """ -def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None) -> array: + +def zeros_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: """ Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. @@ -388,4 +479,22 @@ def zeros_like(x: array, /, *, dtype: Optional[dtype] = None, device: Optional[d an array having the same shape as ``x`` and filled with zeros. """ -__all__ = ['arange', 'asarray', 'empty', 'empty_like', 'eye', 'from_dlpack', 'full', 'full_like', 'linspace', 'meshgrid', 'ones', 'ones_like', 'tril', 'triu', 'zeros', 'zeros_like'] + +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] diff --git a/src/array_api_stubs/_2021_12/data_type_functions.py b/src/array_api_stubs/_2021_12/data_type_functions.py index 2356a8b2e..3567f783f 100644 --- a/src/array_api_stubs/_2021_12/data_type_functions.py +++ b/src/array_api_stubs/_2021_12/data_type_functions.py @@ -1,5 +1,6 @@ from ._types import List, Tuple, Union, array, dtype, finfo_object, iinfo_object + def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: """ Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. @@ -27,6 +28,7 @@ def astype(x: array, dtype: dtype, /, *, copy: bool = True) -> array: an array having the specified data type. The returned array must have the same shape as ``x``. """ + def broadcast_arrays(*arrays: array) -> List[array]: """ Broadcasts one or more arrays against one another. @@ -42,6 +44,7 @@ def broadcast_arrays(*arrays: array) -> List[array]: a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. """ + def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: """ Broadcasts an array to a specified shape. @@ -59,6 +62,7 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: an array having a specified shape. Must have the same data type as ``x``. """ + def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: """ Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. @@ -76,6 +80,7 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. """ + def finfo(type: Union[dtype, array], /) -> finfo_object: """ Machine limits for floating-point data types. @@ -111,6 +116,7 @@ def finfo(type: Union[dtype, array], /) -> finfo_object: smallest positive floating-point number with full precision. """ + def iinfo(type: Union[dtype, array], /) -> iinfo_object: """ Machine limits for integer data types. @@ -138,6 +144,7 @@ def iinfo(type: Union[dtype, array], /) -> iinfo_object: smallest representable number. """ + def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: """ Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. @@ -156,4 +163,13 @@ def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: the dtype resulting from an operation involving the input arrays and dtypes. """ -__all__ = ['astype', 'broadcast_arrays', 'broadcast_to', 'can_cast', 'finfo', 'iinfo', 'result_type'] + +__all__ = [ + "astype", + "broadcast_arrays", + "broadcast_to", + "can_cast", + "finfo", + "iinfo", + "result_type", +] diff --git a/src/array_api_stubs/_2021_12/data_types.py b/src/array_api_stubs/_2021_12/data_types.py index fd00521f1..9a0c24851 100644 --- a/src/array_api_stubs/_2021_12/data_types.py +++ b/src/array_api_stubs/_2021_12/data_types.py @@ -1,5 +1,6 @@ from ._types import dtype + def __eq__(self: dtype, other: dtype, /) -> bool: """ Computes the truth value of ``self == other`` in order to test for data type object equality. @@ -17,4 +18,5 @@ def __eq__(self: dtype, other: dtype, /) -> bool: a boolean indicating whether the data type objects are equal. """ + all = [__eq__] diff --git a/src/array_api_stubs/_2021_12/elementwise_functions.py b/src/array_api_stubs/_2021_12/elementwise_functions.py index bf831d304..2f4478aaa 100644 --- a/src/array_api_stubs/_2021_12/elementwise_functions.py +++ b/src/array_api_stubs/_2021_12/elementwise_functions.py @@ -1,5 +1,6 @@ from ._types import array + def abs(x: array, /) -> array: """ Calculates the absolute value for each element ``x_i`` of the input array ``x`` (i.e., the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign). @@ -26,6 +27,7 @@ def abs(x: array, /) -> array: an array containing the absolute value of each element in ``x``. The returned array must have the same data type as ``x``. """ + def acos(x: array, /) -> array: """ Calculates an implementation-dependent approximation of the principal value of the inverse cosine, having domain ``[-1, +1]`` and codomain ``[+0, +π]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. @@ -50,6 +52,7 @@ def acos(x: array, /) -> array: an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def acosh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the inverse hyperbolic cosine, having domain ``[+1, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -74,6 +77,7 @@ def acosh(x: array, /) -> array: an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def add(x1: array, x2: array, /) -> array: """ Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -116,6 +120,7 @@ def add(x1: array, x2: array, /) -> array: an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. """ + def asin(x: array, /) -> array: """ Calculates an implementation-dependent approximation of the principal value of the inverse sine, having domain ``[-1, +1]`` and codomain ``[-π/2, +π/2]`` for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. @@ -141,6 +146,7 @@ def asin(x: array, /) -> array: an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def asinh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the inverse hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. @@ -166,6 +172,7 @@ def asinh(x: array, /) -> array: an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def atan(x: array, /) -> array: """ Calculates an implementation-dependent approximation of the principal value of the inverse tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-π/2, +π/2]``, for each element ``x_i`` of the input array ``x``. Each element-wise result is expressed in radians. @@ -191,6 +198,7 @@ def atan(x: array, /) -> array: an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def atan2(x1: array, x2: array, /) -> array: """ Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. @@ -244,6 +252,7 @@ def atan2(x1: array, x2: array, /) -> array: """ + def atanh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the inverse hyperbolic tangent, having domain ``[-1, +1]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -271,6 +280,7 @@ def atanh(x: array, /) -> array: an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def bitwise_and(x1: array, x2: array, /) -> array: """ Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -288,6 +298,7 @@ def bitwise_and(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_left_shift(x1: array, x2: array, /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. @@ -305,6 +316,7 @@ def bitwise_left_shift(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_invert(x: array, /) -> array: """ Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. @@ -320,6 +332,7 @@ def bitwise_invert(x: array, /) -> array: an array containing the element-wise results. The returned array must have the same data type as ``x``. """ + def bitwise_or(x1: array, x2: array, /) -> array: """ Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -337,6 +350,7 @@ def bitwise_or(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_right_shift(x1: array, x2: array, /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. @@ -357,6 +371,7 @@ def bitwise_right_shift(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def bitwise_xor(x1: array, x2: array, /) -> array: """ Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -374,6 +389,7 @@ def bitwise_xor(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def ceil(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. @@ -401,6 +417,7 @@ def ceil(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def cos(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the cosine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. @@ -426,6 +443,7 @@ def cos(x: array, /) -> array: an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def cosh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the hyperbolic cosine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` in the input array ``x``. @@ -451,6 +469,7 @@ def cosh(x: array, /) -> array: an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def divide(x1: array, x2: array, /) -> array: """ Calculates the division for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -500,6 +519,7 @@ def divide(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -517,6 +537,7 @@ def equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def exp(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the exponential function, having domain ``[-infinity, +infinity]`` and codomain ``[+0, +infinity]``, for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). @@ -542,6 +563,7 @@ def exp(x: array, /) -> array: an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def expm1(x: array, /) -> array: """ Calculates an implementation-dependent approximation to ``exp(x)-1``, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -570,6 +592,7 @@ def expm1(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def floor(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. @@ -597,6 +620,7 @@ def floor(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def floor_divide(x1: array, x2: array, /) -> array: r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. @@ -653,6 +677,7 @@ def floor_divide(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def greater(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -670,6 +695,7 @@ def greater(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def greater_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -687,6 +713,7 @@ def greater_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def isfinite(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if finite (i.e., not ``NaN`` and not equal to positive or negative infinity). @@ -702,6 +729,7 @@ def isfinite(x: array, /) -> array: an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is finite and ``False`` otherwise. The returned array must have a data type of ``bool``. """ + def isinf(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. @@ -717,6 +745,7 @@ def isinf(x: array, /) -> array: an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is either positive or negative infinity and ``False`` otherwise. The returned array must have a data type of ``bool``. """ + def isnan(x: array, /) -> array: """ Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. @@ -732,6 +761,7 @@ def isnan(x: array, /) -> array: an array containing test results. An element ``out_i`` is ``True`` if ``x_i`` is ``NaN`` and ``False`` otherwise. The returned array should have a data type of ``bool``. """ + def less(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -749,6 +779,7 @@ def less(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def less_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -766,6 +797,7 @@ def less_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def log(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -791,6 +823,7 @@ def log(x: array, /) -> array: an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log1p(x: array, /) -> array: """ Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, having domain ``[-1, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -820,6 +853,7 @@ def log1p(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log2(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the base ``2`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -845,6 +879,7 @@ def log2(x: array, /) -> array: an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def log10(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the base ``10`` logarithm, having domain ``[0, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -870,6 +905,7 @@ def log10(x: array, /) -> array: an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def logaddexp(x1: array, x2: array, /) -> array: """ Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -895,6 +931,7 @@ def logaddexp(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def logical_and(x1: array, x2: array, /) -> array: """ Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -915,6 +952,7 @@ def logical_and(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of `bool`. """ + def logical_not(x: array, /) -> array: """ Computes the logical NOT for each element ``x_i`` of the input array ``x``. @@ -933,6 +971,7 @@ def logical_not(x: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def logical_or(x1: array, x2: array, /) -> array: """ Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -953,6 +992,7 @@ def logical_or(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def logical_xor(x1: array, x2: array, /) -> array: """ Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -973,6 +1013,7 @@ def logical_xor(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def multiply(x1: array, x2: array, /) -> array: """ Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1007,6 +1048,7 @@ def multiply(x1: array, x2: array, /) -> array: an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. """ + def negative(x: array, /) -> array: """ Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. @@ -1025,6 +1067,7 @@ def negative(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def not_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1042,6 +1085,7 @@ def not_equal(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type of ``bool``. """ + def positive(x: array, /) -> array: """ Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. @@ -1057,6 +1101,7 @@ def positive(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def pow(x1: array, x2: array, /) -> array: """ Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. @@ -1108,6 +1153,7 @@ def pow(x1: array, x2: array, /) -> array: an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. """ + def remainder(x1: array, x2: array, /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. @@ -1159,6 +1205,7 @@ def remainder(x1: array, x2: array, /) -> array: an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def round(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. @@ -1187,6 +1234,7 @@ def round(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def sign(x: array, /) -> array: """ Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. @@ -1208,6 +1256,7 @@ def sign(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. """ + def sin(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the sine, having domain ``(-infinity, +infinity)`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. @@ -1232,6 +1281,7 @@ def sin(x: array, /) -> array: an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def sinh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the hyperbolic sine, having domain ``[-infinity, +infinity]`` and codomain ``[-infinity, +infinity]``, for each element ``x_i`` of the input array ``x``. @@ -1257,6 +1307,7 @@ def sinh(x: array, /) -> array: an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def square(x: array, /) -> array: """ Squares (``x_i * x_i``) each element ``x_i`` of the input array ``x``. @@ -1272,6 +1323,7 @@ def square(x: array, /) -> array: an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def sqrt(x: array, /) -> array: """ Calculates the square root, having domain ``[0, +infinity]`` and codomain ``[0, +infinity]``, for each element ``x_i`` of the input array ``x``. After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). @@ -1297,6 +1349,7 @@ def sqrt(x: array, /) -> array: an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def subtract(x1: array, x2: array, /) -> array: """ Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). @@ -1314,6 +1367,7 @@ def subtract(x1: array, x2: array, /) -> array: an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. """ + def tan(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the tangent, having domain ``(-infinity, +infinity)`` and codomain ``(-infinity, +infinity)``, for each element ``x_i`` of the input array ``x``. Each element ``x_i`` is assumed to be expressed in radians. @@ -1338,6 +1392,7 @@ def tan(x: array, /) -> array: an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def tanh(x: array, /) -> array: """ Calculates an implementation-dependent approximation to the hyperbolic tangent, having domain ``[-infinity, +infinity]`` and codomain ``[-1, +1]``, for each element ``x_i`` of the input array ``x``. @@ -1363,6 +1418,7 @@ def tanh(x: array, /) -> array: an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def trunc(x: array, /) -> array: """ Rounds each element ``x_i`` of the input array ``x`` to the integer-valued number that is closest to but no greater than ``x_i``. @@ -1390,4 +1446,62 @@ def trunc(x: array, /) -> array: an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. """ -__all__ = ['abs', 'acos', 'acosh', 'add', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'bitwise_and', 'bitwise_left_shift', 'bitwise_invert', 'bitwise_or', 'bitwise_right_shift', 'bitwise_xor', 'ceil', 'cos', 'cosh', 'divide', 'equal', 'exp', 'expm1', 'floor', 'floor_divide', 'greater', 'greater_equal', 'isfinite', 'isinf', 'isnan', 'less', 'less_equal', 'log', 'log1p', 'log2', 'log10', 'logaddexp', 'logical_and', 'logical_not', 'logical_or', 'logical_xor', 'multiply', 'negative', 'not_equal', 'positive', 'pow', 'remainder', 'round', 'sign', 'sin', 'sinh', 'square', 'sqrt', 'subtract', 'tan', 'tanh', 'trunc'] + +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "remainder", + "round", + "sign", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 6a0348129..4e4ba52b2 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -1,6 +1,7 @@ from ._types import Literal, Optional, Tuple, Union, Sequence, array from .constants import inf + def cholesky(x: array, /, *, upper: bool = False) -> array: """ Returns the lower (upper) Cholesky decomposition x = LLᵀ (x = UᵀU) of a symmetric positive-definite matrix (or a stack of matrices) ``x``, where ``L`` is a lower-triangular matrix or a stack of matrices (``U`` is an upper-triangular matrix or a stack of matrices). @@ -24,6 +25,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ + def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Returns the cross product of 3-element vectors. If ``x1`` and ``x2`` are multi-dimensional arrays (i.e., both have a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. @@ -43,6 +45,7 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. """ + def det(x: array, /) -> array: """ Returns the determinant of a square matrix (or a stack of square matrices) ``x``. @@ -58,6 +61,7 @@ def det(x: array, /) -> array: if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. """ + def diagonal(x: array, /, *, offset: int = 0) -> array: """ Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. @@ -81,6 +85,7 @@ def diagonal(x: array, /, *, offset: int = 0) -> array: an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. """ + def eigh(x: array, /) -> Tuple[array]: """ Returns an eigendecomposition x = QLQᵀ of a symmetric matrix (or a stack of symmetric matrices) ``x``, where ``Q`` is an orthogonal matrix (or a stack of matrices) and ``L`` is a vector (or a stack of vectors). @@ -113,6 +118,7 @@ def eigh(x: array, /) -> Tuple[array]: Eigenvalue sort order is left unspecified and is thus implementation-dependent. """ + def eigvalsh(x: array, /) -> array: """ Returns the eigenvalues of a symmetric matrix (or a stack of symmetric matrices) ``x``. @@ -140,6 +146,7 @@ def eigvalsh(x: array, /) -> array: Eigenvalue sort order is left unspecified and is thus implementation-dependent. """ + def inv(x: array, /) -> array: """ Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. @@ -155,12 +162,20 @@ def inv(x: array, /) -> array: an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. """ + def matmul(x1: array, x2: array, /) -> array: """ Alias for :func:`~array_api.matmul`. """ -def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] = 'fro') -> array: + +def matrix_norm( + x: array, + /, + *, + keepdims: bool = False, + ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro", +) -> array: """ Computes the matrix norm of a matrix (or a stack of matrices) ``x``. @@ -213,6 +228,7 @@ def matrix_norm(x: array, /, *, keepdims: bool = False, ord: Optional[Union[int, an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def matrix_power(x: array, n: int, /) -> array: """ Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. @@ -230,6 +246,7 @@ def matrix_power(x: array, n: int, /) -> array: if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. """ + def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: """ Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). @@ -247,11 +264,13 @@ def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> a an array containing the ranks. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). """ + def matrix_transpose(x: array, /) -> array: """ Alias for :func:`~array_api.matrix_transpose`. """ + def outer(x1: array, x2: array, /) -> array: """ Returns the outer product of two vectors ``x1`` and ``x2``. @@ -269,6 +288,7 @@ def outer(x1: array, x2: array, /) -> array: a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: """ Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. @@ -286,7 +306,10 @@ def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: an array containing the pseudo-inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). """ -def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tuple[array, array]: + +def qr( + x: array, /, *, mode: Literal["reduced", "complete"] = "reduced" +) -> Tuple[array, array]: """ Returns the qr decomposition x = QR of a full column rank matrix (or a stack of matrices), where ``Q`` is an orthonormal matrix (or a stack of matrices) and ``R`` is an upper-triangular matrix (or a stack of matrices). @@ -316,6 +339,7 @@ def qr(x: array, /, *, mode: Literal['reduced', 'complete'] = 'reduced') -> Tupl Each returned array must have a floating-point data type determined by :ref:`type-promotion`. """ + def slogdet(x: array, /) -> Tuple[array, array]: """ Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. @@ -344,6 +368,7 @@ def slogdet(x: array, /) -> Tuple[array, array]: If a determinant is zero, then the corresponding ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``; however, depending on the underlying algorithm, the returned result may differ. In all cases, the determinant should be equal to ``sign * exp(logsabsdet)`` (although, again, the result may be subject to numerical precision errors). """ + def solve(x1: array, x2: array, /) -> array: """ Returns the solution to the system of linear equations represented by the well-determined (i.e., full rank) linear matrix equation ``AX = B``. @@ -364,6 +389,7 @@ def solve(x1: array, x2: array, /) -> array: an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. """ + def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: """ Returns a singular value decomposition A = USVh of a matrix (or a stack of matrices) ``x``, where ``U`` is a matrix (or a stack of matrices) with orthonormal columns, ``S`` is a vector of non-negative numbers (or stack of vectors), and ``Vh`` is a matrix (or a stack of matrices) with orthonormal rows. @@ -389,6 +415,7 @@ def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array Each returned array must have the same floating-point data type as ``x``. """ + def svdvals(x: array, /) -> array: """ Returns the singular values of a matrix (or a stack of matrices) ``x``. @@ -404,11 +431,19 @@ def svdvals(x: array, /) -> array: an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have the same floating-point data type as ``x``. """ -def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: """ Alias for :func:`~array_api.tensordot`. """ + def trace(x: array, /, *, offset: int = 0) -> array: """ Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. @@ -438,12 +473,21 @@ def trace(x: array, /, *, offset: int = 0) -> array: The returned array must have the same data type as ``x``. """ + def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: """ Alias for :func:`~array_api.vecdot`. """ -def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False, ord: Union[int, float, Literal[inf, -inf]] = 2) -> array: + +def vector_norm( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, + ord: Union[int, float, Literal[inf, -inf]] = 2, +) -> array: r""" Computes the vector norm of a vector (or batch of vectors) ``x``. @@ -494,4 +538,29 @@ def vector_norm(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = No an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. """ -__all__ = ['cholesky', 'cross', 'det', 'diagonal', 'eigh', 'eigvalsh', 'inv', 'matmul', 'matrix_norm', 'matrix_power', 'matrix_rank', 'matrix_transpose', 'outer', 'pinv', 'qr', 'slogdet', 'solve', 'svd', 'svdvals', 'tensordot', 'trace', 'vecdot', 'vector_norm'] + +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] diff --git a/src/array_api_stubs/_2021_12/linear_algebra_functions.py b/src/array_api_stubs/_2021_12/linear_algebra_functions.py index a2defaf1b..0b5cbfdb7 100644 --- a/src/array_api_stubs/_2021_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2021_12/linear_algebra_functions.py @@ -1,5 +1,6 @@ from ._types import Tuple, Union, Sequence, array + def matmul(x1: array, x2: array, /) -> array: """ Computes the matrix product. @@ -37,6 +38,7 @@ def matmul(x1: array, x2: array, /) -> array: - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. """ + def matrix_transpose(x: array, /) -> array: """ Transposes a matrix (or a stack of matrices) ``x``. @@ -52,7 +54,14 @@ def matrix_transpose(x: array, /) -> array: an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. """ -def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2) -> array: + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: """ Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. @@ -83,6 +92,7 @@ def tensordot(x1: array, x2: array, /, *, axes: Union[int, Tuple[Sequence[int], an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. """ + def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Computes the (vector) dot product of two arrays. @@ -108,4 +118,5 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: - if the size of the axis over which to compute the dot product is not the same for both ``x1`` and ``x2``. """ -__all__ = ['matmul', 'matrix_transpose', 'tensordot', 'vecdot'] + +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] diff --git a/src/array_api_stubs/_2021_12/manipulation_functions.py b/src/array_api_stubs/_2021_12/manipulation_functions.py index 64c05db35..8ae359a3a 100644 --- a/src/array_api_stubs/_2021_12/manipulation_functions.py +++ b/src/array_api_stubs/_2021_12/manipulation_functions.py @@ -1,6 +1,9 @@ from ._types import List, Optional, Tuple, Union, array -def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0) -> array: + +def concat( + arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0 +) -> array: """ Joins a sequence of arrays along an existing axis. @@ -20,6 +23,7 @@ def concat(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[i This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. """ + def expand_dims(x: array, /, *, axis: int = 0) -> array: """ Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. @@ -37,6 +41,7 @@ def expand_dims(x: array, /, *, axis: int = 0) -> array: an expanded output array having the same data type as ``x``. """ + def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: """ Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. @@ -54,6 +59,7 @@ def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. """ + def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: """ Permutes the axes (dimensions) of an array ``x``. @@ -71,7 +77,10 @@ def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: an array containing the axes permutation. The returned array must have the same data type as ``x``. """ -def reshape(x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None) -> array: + +def reshape( + x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None +) -> array: """ Reshapes an array without changing its data. @@ -90,7 +99,14 @@ def reshape(x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None) an output array having the same data type and elements as ``x``. """ -def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + +def roll( + x: array, + /, + shift: Union[int, Tuple[int, ...]], + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, +) -> array: """ Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. @@ -109,6 +125,7 @@ def roll(x: array, /, shift: Union[int, Tuple[int, ...]], *, axis: Optional[Unio an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. """ + def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: """ Removes singleton dimensions (axes) from ``x``. @@ -126,6 +143,7 @@ def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: an output array having the same data type and elements as ``x``. """ + def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: """ Joins a sequence of arrays along a new axis. @@ -146,4 +164,14 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. """ -__all__ = ['concat', 'expand_dims', 'flip', 'permute_dims', 'reshape', 'roll', 'squeeze', 'stack'] \ No newline at end of file + +__all__ = [ + "concat", + "expand_dims", + "flip", + "permute_dims", + "reshape", + "roll", + "squeeze", + "stack", +] diff --git a/src/array_api_stubs/_2021_12/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py index c2875adcc..14ebdd889 100644 --- a/src/array_api_stubs/_2021_12/searching_functions.py +++ b/src/array_api_stubs/_2021_12/searching_functions.py @@ -1,5 +1,6 @@ from ._types import Optional, Tuple, array + def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ Returns the indices of the maximum values along a specified axis. When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. @@ -19,6 +20,7 @@ def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. """ + def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: """ Returns the indices of the minimum values along a specified axis. When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. @@ -38,6 +40,7 @@ def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. """ + def nonzero(x: array, /) -> Tuple[array, ...]: """ Returns the indices of the array elements which are non-zero. @@ -58,6 +61,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. """ + def where(condition: array, x1: array, x2: array, /) -> array: """ Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. @@ -77,4 +81,5 @@ def where(condition: array, x1: array, x2: array, /) -> array: an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. """ -__all__ = ['argmax', 'argmin', 'nonzero', 'where'] + +__all__ = ["argmax", "argmin", "nonzero", "where"] diff --git a/src/array_api_stubs/_2021_12/set_functions.py b/src/array_api_stubs/_2021_12/set_functions.py index bd24e5323..eb5c1d951 100644 --- a/src/array_api_stubs/_2021_12/set_functions.py +++ b/src/array_api_stubs/_2021_12/set_functions.py @@ -1,5 +1,6 @@ from ._types import Tuple, array + 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``. @@ -39,6 +40,7 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_counts(x: array, /) -> Tuple[array, array]: """ Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. @@ -73,6 +75,7 @@ def unique_counts(x: array, /) -> Tuple[array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_inverse(x: array, /) -> Tuple[array, array]: """ Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. @@ -107,6 +110,7 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: The order of unique elements is not specified and may vary between implementations. """ + def unique_values(x: array, /) -> array: """ Returns the unique elements of an input array ``x``. @@ -136,4 +140,5 @@ def unique_values(x: array, /) -> array: The order of unique elements is not specified and may vary between implementations. """ -__all__ = ['unique_all', 'unique_counts', 'unique_inverse', 'unique_values'] \ No newline at end of file + +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] diff --git a/src/array_api_stubs/_2021_12/sorting_functions.py b/src/array_api_stubs/_2021_12/sorting_functions.py index 715a3e817..59d3a3c68 100644 --- a/src/array_api_stubs/_2021_12/sorting_functions.py +++ b/src/array_api_stubs/_2021_12/sorting_functions.py @@ -1,6 +1,9 @@ from ._types import array -def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + +def argsort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: """ Returns the indices that sort an array ``x`` along a specified axis. @@ -21,7 +24,10 @@ def argsort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bo an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. """ -def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True) -> array: + +def sort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: """ Returns a sorted copy of an input array ``x``. @@ -42,4 +48,5 @@ def sort(x: array, /, *, axis: int = -1, descending: bool = False, stable: bool a sorted array. The returned array must have the same data type and shape as ``x``. """ -__all__ = ['argsort', 'sort'] \ No newline at end of file + +__all__ = ["argsort", "sort"] diff --git a/src/array_api_stubs/_2021_12/statistical_functions.py b/src/array_api_stubs/_2021_12/statistical_functions.py index 4265f28f5..a436535f7 100644 --- a/src/array_api_stubs/_2021_12/statistical_functions.py +++ b/src/array_api_stubs/_2021_12/statistical_functions.py @@ -1,6 +1,13 @@ from ._types import Optional, Tuple, Union, array, dtype -def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def max( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the maximum value of the input array ``x``. @@ -28,7 +35,14 @@ def max(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. """ -def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def mean( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the arithmetic mean of the input array ``x``. @@ -57,7 +71,14 @@ def mean(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, kee While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. """ -def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def min( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Calculates the minimum value of the input array ``x``. @@ -85,7 +106,15 @@ def min(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. """ -def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + +def prod( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: """ Calculates the product of input array ``x`` elements. @@ -127,7 +156,15 @@ def prod(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dty if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. """ -def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + +def std( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: """ Calculates the standard deviation of the input array ``x``. @@ -158,7 +195,15 @@ def std(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. """ -def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtype: Optional[dtype] = None, keepdims: bool = False) -> array: + +def sum( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: """ Calculates the sum of the input array ``x``. @@ -200,7 +245,15 @@ def sum(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, dtyp if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. """ -def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, correction: Union[int, float] = 0.0, keepdims: bool = False) -> array: + +def var( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: """ Calculates the variance of the input array ``x``. @@ -232,4 +285,5 @@ def var(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, corr While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default floating-point data type. """ -__all__ = ['max', 'mean', 'min', 'prod', 'std', 'sum', 'var'] + +__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] diff --git a/src/array_api_stubs/_2021_12/utility_functions.py b/src/array_api_stubs/_2021_12/utility_functions.py index 79423f455..847182abd 100644 --- a/src/array_api_stubs/_2021_12/utility_functions.py +++ b/src/array_api_stubs/_2021_12/utility_functions.py @@ -1,6 +1,13 @@ from ._types import Optional, Tuple, Union, array -def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def all( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Tests whether all input array elements evaluate to ``True`` along a specified axis. @@ -25,7 +32,14 @@ def all(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. """ -def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keepdims: bool = False) -> array: + +def any( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ Tests whether any input array element evaluates to ``True`` along a specified axis. @@ -50,4 +64,5 @@ def any(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None, keep if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. """ -__all__ = ['all', 'any'] + +__all__ = ["all", "any"] diff --git a/src/array_api_stubs/_2022_12/_types.py b/src/array_api_stubs/_2022_12/_types.py index 589606784..837a7806f 100644 --- a/src/array_api_stubs/_2022_12/_types.py +++ b/src/array_api_stubs/_2022_12/_types.py @@ -34,6 +34,7 @@ @dataclass class finfo_object: """Dataclass returned by `finfo`.""" + bits: int eps: float max: float @@ -41,14 +42,17 @@ class finfo_object: smallest_normal: float dtype: dtype + @dataclass class iinfo_object: """Dataclass returned by `iinfo`.""" + bits: int max: int min: int dtype: dtype + _T_co = TypeVar("_T_co", covariant=True) From 9dbdec0656c89e41ccbcc1d82723f293bcb8ff9f Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 15 Sep 2023 14:38:51 +0200 Subject: [PATCH 446/551] Add a git-blame-ignore-revs entry for style changes in previous commit --- .git-blame-ignore-revs | 1 + 1 file changed, 1 insertion(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 4fd6df5d4..3d9e87daa 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,5 +1,6 @@ # Migrate code style to Black 162034b12711dad54589c5dc9e75942695a7957f +678f9eab5a593005e7bb80a46156c27b210cfcea # Move special cases to notes sections 816fba3b75c38cbb1bb6fe5b1342adc5eab694f3 From 149d340c77e3166a9e60a7ff75621769818780ca Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Tue, 19 Sep 2023 14:38:12 -0700 Subject: [PATCH 447/551] Fix lint error --- src/array_api_stubs/_draft/manipulation_functions.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2b6689647..4c2a4ab4a 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -115,7 +115,12 @@ def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> """ -def moveaxis(x: array, source: Union[int, Tuple[int, ...]], destination: Union[int, Tuple[int, ...]], /) -> array: +def moveaxis( + x: array, + source: Union[int, Tuple[int, ...]], + destination: Union[int, Tuple[int, ...]], + / +) -> array: """ Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. From f05c22fb42bd3c69b1589ef9c7162ebf33a12d09 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Tue, 19 Sep 2023 14:44:54 -0700 Subject: [PATCH 448/551] Fix index range --- src/array_api_stubs/_draft/manipulation_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 4c2a4ab4a..4bfeb1caa 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -129,9 +129,9 @@ def moveaxis( x: array input array. source: Union[int, Tuple[int, ...]] - Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. destination: Union[int, Tuple[int, ...]] - indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the open-interval ``(-N, N)``. + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. Returns ------- From 8149b33b51bf2d7064bd72731d99ccc31e9cc265 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Tue, 19 Sep 2023 14:45:49 -0700 Subject: [PATCH 449/551] Fix lint error --- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 4bfeb1caa..2bc929134 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -119,7 +119,7 @@ def moveaxis( x: array, source: Union[int, Tuple[int, ...]], destination: Union[int, Tuple[int, ...]], - / + /, ) -> array: """ Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. From f7aa6805f598b810e596e296a1c0d5d4e51b70f9 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:12:28 -0700 Subject: [PATCH 450/551] Revert removed exported symbols --- src/array_api_stubs/_draft/data_type_functions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 8243d7986..2301fc196 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -1,3 +1,5 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + from ._types import ( Union, Tuple, From 430c96751b59ff33c3825b859f473ad1a3bbf58d Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:14:34 -0700 Subject: [PATCH 451/551] Update copy --- src/array_api_stubs/_draft/data_type_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 2301fc196..0f089c889 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -46,7 +46,7 @@ def astype( copy: bool specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. device: Optional[device] - device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. Returns ------- From c33c508114e0f846d6ede134bf679ad88e0ef5ca Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:16:51 -0700 Subject: [PATCH 452/551] Fix lint error --- src/array_api_stubs/_draft/data_type_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 0f089c889..11533f7f2 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -8,7 +8,7 @@ finfo_object, iinfo_object, device, - Optional + Optional, ) From 1c6c73c29a45eba6963981a77324c3dce66b16f4 Mon Sep 17 00:00:00 2001 From: Athan Date: Tue, 19 Sep 2023 15:18:14 -0700 Subject: [PATCH 453/551] Fix lint error --- src/array_api_stubs/_draft/data_type_functions.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 11533f7f2..81d518807 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -13,8 +13,7 @@ def astype( - x: array, dtype: dtype, /, *, copy: bool = True, - device: Optional[device] = None + x: array, dtype: dtype, /, *, copy: bool = True, device: Optional[device] = None ) -> array: """ Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. From 8c42f02add07e6f4423335a4c71dd7f91b37cf84 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 19 Sep 2023 19:29:13 -0500 Subject: [PATCH 454/551] Allow negative axes in tensordot PR-URL: https://github.com/data-apis/array-api/pull/625 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/linear_algebra_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index a6f84e392..079a90ee6 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -92,7 +92,7 @@ def tensordot( Contracted axes (dimensions) must not be broadcasted. axes: Union[int, Tuple[Sequence[int], Sequence[int]]] - number of axes (dimensions) to contract or explicit sequences of axes (dimensions) for ``x1`` and ``x2``, respectively. + number of axes (dimensions) to contract or explicit sequences of axis (dimension) indices for ``x1`` and ``x2``, respectively. If ``axes`` is an ``int`` equal to ``N``, then contraction must be performed over the last ``N`` axes of ``x1`` and the first ``N`` axes of ``x2`` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. @@ -100,7 +100,7 @@ def tensordot( - If ``N`` equals ``1``, the result is the tensor dot product. - If ``N`` equals ``2``, the result is the tensor double contraction (default). - If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each sequence must consist of unique (nonnegative) integers that specify valid axes for each respective array. + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each index referred to in a sequence must be unique. If ``x1`` has rank (i.e, number of dimensions) ``N``, a valid ``x1`` axis must reside on the half-open interval ``[-N, N)``. If ``x2`` has rank ``M``, a valid ``x2`` axis must reside on the half-open interval ``[-M, M)``. .. note:: From 03886d61efdd0cb11302da8043d0aa65b3c03bbf Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Oct 2023 16:44:46 -0700 Subject: [PATCH 455/551] Add support for `copysign` to the specification PR-URL: https://github.com/data-apis/array-api/pull/693 --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 42 +++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 0e5fd0609..8048eb38a 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -34,6 +34,7 @@ Objects in API bitwise_xor ceil conj + copysign cos cosh divide diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 147eff9cd..faaa9213b 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -16,6 +16,7 @@ "bitwise_xor", "ceil", "conj", + "copysign", "cos", "cosh", "divide", @@ -804,6 +805,47 @@ def conj(x: array, /) -> array: """ +def copysign(x1: array, x2: array, /) -> array: + r""" + Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. + + Parameters + ---------- + x1: array + input array containing magnitudes. Should have a real-valued floating-point data type. + x2: array + input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``-0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``+0``, the result is ``|x1_i|``. + - If ``x2_i`` is greater than ``0``, the result is ``|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. + + If ``x1_i`` is ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + """ + + def cos(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. From 2bcf7c048f9f38f1529beddf7a6c0a9627cd5cfe Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Oct 2023 19:01:48 -0700 Subject: [PATCH 456/551] Add support for tiling an array to the specification PR-URL: https://github.com/data-apis/array-api/pull/692 Co-authored-by: Oleksandr Pavlyk --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 25 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index 7eb7fa8b0..680efb55f 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -29,4 +29,5 @@ Objects in API roll squeeze stack + tile unstack diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 2bc929134..74538a8a3 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -10,6 +10,7 @@ "roll", "squeeze", "stack", + "tile", "unstack", ] @@ -257,6 +258,30 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ +def tile(x: array, repetitions: Tuple[int, ...], /): + """ + Constructs an array by tiling an input array. + + Parameters + ---------- + x: array + input array. + repetitions: Tuple[int, ...] + number of repetitions along each axis (dimension). + + Let ``N = len(x.shape)`` and ``M = len(repetitions)``. + + If ``N > M``, the function must prepend ones until all axes (dimensions) are specified (e.g., if ``x`` has shape ``(8,6,4,2)`` and ``repetitions`` is the tuple ``(3,3)``, then ``repetitions`` must be treated as ``(1,1,3,3)``). + + If ``N < M``, the function must prepend singleton axes (dimensions) to ``x`` until ``x`` has as many axes (dimensions) as ``repetitions`` specifies (e.g., if ``x`` has shape ``(4,2)`` and ``repetitions`` is the tuple ``(3,3,3,3)``, then ``x`` must be treated as if it has shape ``(1,1,4,2)``). + + Returns + ------- + out: array + a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + """ + + def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: """ Splits an array in a sequence of arrays along the given axis. From 0f64005c7af6cc1906f310e929d0b8fcac24fd41 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 5 Nov 2023 20:23:35 -0800 Subject: [PATCH 457/551] Backport type fixes to `__getitem__` to previous specification revisions PR-URL: https://github.com/data-apis/array-api/pull/687 Reviewed-by: Matthew Barber Ref: https://github.com/data-apis/array-api/pull/674 --- spec/draft/API_specification/indexing.rst | 3 +++ src/array_api_stubs/_2021_12/array_object.py | 9 +++++++-- src/array_api_stubs/_2022_12/array_object.py | 9 +++++++-- src/array_api_stubs/_draft/array_object.py | 9 +++++++-- 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/spec/draft/API_specification/indexing.rst b/spec/draft/API_specification/indexing.rst index 6d5e77a5b..eb61c26d5 100644 --- a/spec/draft/API_specification/indexing.rst +++ b/spec/draft/API_specification/indexing.rst @@ -156,6 +156,9 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult .. note:: Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. + .. note:: + The constant ``newaxis`` is an alias of ``None`` and can thus be used in a similar manner as ``None``. + - Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. .. note:: diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index 9aa7119d0..528e0a286 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -453,7 +453,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, ], /, ) -> array: @@ -464,7 +469,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index 6cac6033d..b8f703996 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -477,7 +477,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, ], /, ) -> array: @@ -488,7 +493,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 2976b46b2..e934c0bec 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -479,7 +479,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: def __getitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, ], /, ) -> array: @@ -490,7 +495,7 @@ def __getitem__( ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, None], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] index key. Returns From ab69aa240025ff1d52525ce3859b69ebfd6b7faf Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 16 Nov 2023 06:07:50 -0800 Subject: [PATCH 458/551] fix: correct typo in data type (#706) --- src/array_api_stubs/_2022_12/elementwise_functions.py | 2 +- src/array_api_stubs/_draft/elementwise_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index 28768e9d9..9139612e8 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -727,7 +727,7 @@ def conj(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex-floating point data type. + input array. Should have a complex floating-point data type. Returns ------- diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index faaa9213b..e3988a09f 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -791,7 +791,7 @@ def conj(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex-floating point data type. + input array. Should have a complex floating-point data type. Returns ------- From 267a41ce079481e25e4a8d3634184d636ea379b9 Mon Sep 17 00:00:00 2001 From: Christian Bourjau Date: Thu, 16 Nov 2023 16:31:43 +0100 Subject: [PATCH 459/551] Allow lazy implementations to raise from intrinsically eager functions (#652) --- src/array_api_stubs/_draft/array_object.py | 26 ++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index e934c0bec..03d62590d 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -241,6 +241,10 @@ def __bool__(self: array, /) -> bool: For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + **Lazy implementations** + + The Python language requires the return value to be of type ``bool``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionchanged:: 2022.12 Added boolean and complex data type support. """ @@ -276,6 +280,10 @@ def __complex__(self: array, /) -> complex: - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. - If ``self`` is a finite number, the result is ``self + 0j``. + **Lazy implementations** + + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionadded:: 2022.12 """ @@ -424,6 +432,10 @@ def __float__(self: array, /) -> float: - If ``self`` is ``True``, the result is ``1``. - If ``self`` is ``False``, the result is ``0``. + **Lazy implementations** + + The Python language requires the return value to be of type ``float``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionchanged:: 2022.12 Added boolean and complex data type support. """ @@ -544,6 +556,13 @@ def __index__(self: array, /) -> int: ------- out: int a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. """ def __int__(self: array, /) -> int: @@ -582,6 +601,13 @@ def __int__(self: array, /) -> int: - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. - If ``self`` is ``NaN``, raise ``ValueError``. + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + .. versionchanged:: 2022.12 Added boolean and complex data type support. """ From bbb40017c3c51fe9237c794424e889e21a325486 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 16 Nov 2023 17:42:16 +0100 Subject: [PATCH 460/551] Fix a minor formatting issue that `black` is unhappy about --- src/array_api_stubs/_draft/array_object.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 03d62590d..600e947e0 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -282,7 +282,7 @@ def __complex__(self: array, /) -> complex: **Lazy implementations** - The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. .. versionadded:: 2022.12 """ From 200d016ca8a61997f0da2f657cd4560ac098249d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 27 Nov 2023 10:56:46 +0100 Subject: [PATCH 461/551] Add a design topic page on lazy vs. eager implementations (#708) Follow-up to gh-652, which added notes to the specifications for `__bool__` & co on this topic. --- spec/draft/design_topics/index.rst | 1 + spec/draft/design_topics/lazy_eager.rst | 43 +++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 spec/draft/design_topics/lazy_eager.rst diff --git a/spec/draft/design_topics/index.rst b/spec/draft/design_topics/index.rst index fa26359a7..548eda90c 100644 --- a/spec/draft/design_topics/index.rst +++ b/spec/draft/design_topics/index.rst @@ -7,6 +7,7 @@ Design topics & constraints copies_views_and_mutation data_dependent_output_shapes + lazy_eager data_interchange device_support static_typing diff --git a/spec/draft/design_topics/lazy_eager.rst b/spec/draft/design_topics/lazy_eager.rst new file mode 100644 index 000000000..63297ac73 --- /dev/null +++ b/spec/draft/design_topics/lazy_eager.rst @@ -0,0 +1,43 @@ +.. _lazy-eager: + +Lazy vs. eager execution +======================== + +While the execution model for implementations is out of scope of this standard, +there are a few aspects of lazy (or graph-based) execution as contrasted to +eager execution that may have an impact on the prescribed semantics of +individual APIs, and will therefore show up in the API specification. + +One important difference is data-dependent or value-dependent behavior, as +described in :ref:`data-dependent-output-shapes`. Because such behavior is hard +to implement, implementers may choose to omit such APIs from their library. + +Another difference is when the Python language itself prescribes that a +specific type *must* be returned. For those cases, it is not possible to return +a lazy/delayed kind of object to avoid computing a value. This is the case for +five dunder methods: `__bool__`, `__int__`, `__float__`, `__complex__` and +`__index__`. Each implementation has only two choices when one of these methods +is called: + +1. Compute a value of the required type (a Python scalar of type `bool`, `int`, + `float` or `complex`), or +2. Raise an exception. + +When an implementation is 100% lazy, for example when it serializes a +computation graph, computing the value is not possible and hence such an +implementation has no choice but to raise an exception. For a "mostly lazy" +implementation, it may make sense to trigger execution instead - but it is not +required to, both choices are valid. + +A common code construct where this happens is conditional logic, e.g.:: + + vals = compute_something() + if all(vals): + # The if-statement will make Python call the __bool__ method + # on the result of `all(vals)`. + do_something_else() + +Note that the API does not contain control flow constructs, as of now, that +would allow avoiding the implicit `__bool__` call in the example above. The +only control flow-like function is `where`, but there's no function like `cond` +to replace an `if`-statement. From 5555d41466d8f326ba550ba293ab94fdefeae9ab Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 29 Nov 2023 21:20:16 -0800 Subject: [PATCH 462/551] Revise guidance to require a minimum upper bound for supported ranks PR-URL: https://github.com/data-apis/array-api/pull/702 Reviewed-by: Ralf Gommers Reviewed-by: Leo Fang --- spec/draft/API_specification/array_object.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/draft/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst index b15bbdc43..0fadf9fc5 100644 --- a/spec/draft/API_specification/array_object.rst +++ b/spec/draft/API_specification/array_object.rst @@ -7,7 +7,7 @@ Array object A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods. -Furthermore, a conforming implementation of the array API standard must support array objects of arbitrary rank ``N`` (i.e., number of dimensions), where ``N`` is greater than or equal to zero. +Furthermore, a conforming implementation of the array API standard must support, at minimum, array objects of rank (i.e., number of dimensions) ``0``, ``1``, ``2``, ``3``, and ``4`` and must explicitly document their maximum supported rank ``N``. .. note:: Conforming implementations must support zero-dimensional arrays. From f5d83044b3b6fcc96baeec24a99aacec8b1600d7 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 30 Nov 2023 02:02:50 -0800 Subject: [PATCH 463/551] Remove outdated content from Purpose and Scope document (#714) * Remove outdated content from Purpose and Scope document * Fix typo * Backport content updates to the 2022 revision --- spec/2022.12/purpose_and_scope.md | 7 +++---- spec/draft/purpose_and_scope.md | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/spec/2022.12/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md index eee3c7f4c..38287f270 100644 --- a/spec/2022.12/purpose_and_scope.md +++ b/spec/2022.12/purpose_and_scope.md @@ -144,7 +144,7 @@ standard is shown in this diagram: _Rationale: execution is the domain of implementations. Attempting to specify execution behavior in a standard is likely to require much more fine-grained coordination between developers of implementations, and hence is likely to - become an obstable to adoption._ + become an obstacle to adoption._ 3. Non-Python API standardization (e.g., Cython or NumPy C APIs) @@ -153,14 +153,13 @@ standard is shown in this diagram: this point in time to standardize anything. See the [C API section](design_topics/C_API.md) for more details._ -4. Standardization of these dtypes is out of scope: bfloat16, complex, extended +4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. _Rationale: these dtypes aren't uniformly supported, and their inclusion at this point in time could put a significant implementation burden on libraries. It is expected that some of these dtypes - in particular - `bfloat16`, `complex64`, and `complex128` - will be included in a future - version of the standard._ + `bfloat16` - will be included in a future version of the standard._ 5. The following topics are out of scope: I/O, polynomials, error handling, testing routines, building and packaging related functionality, methods of diff --git a/spec/draft/purpose_and_scope.md b/spec/draft/purpose_and_scope.md index eee3c7f4c..38287f270 100644 --- a/spec/draft/purpose_and_scope.md +++ b/spec/draft/purpose_and_scope.md @@ -144,7 +144,7 @@ standard is shown in this diagram: _Rationale: execution is the domain of implementations. Attempting to specify execution behavior in a standard is likely to require much more fine-grained coordination between developers of implementations, and hence is likely to - become an obstable to adoption._ + become an obstacle to adoption._ 3. Non-Python API standardization (e.g., Cython or NumPy C APIs) @@ -153,14 +153,13 @@ standard is shown in this diagram: this point in time to standardize anything. See the [C API section](design_topics/C_API.md) for more details._ -4. Standardization of these dtypes is out of scope: bfloat16, complex, extended +4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. _Rationale: these dtypes aren't uniformly supported, and their inclusion at this point in time could put a significant implementation burden on libraries. It is expected that some of these dtypes - in particular - `bfloat16`, `complex64`, and `complex128` - will be included in a future - version of the standard._ + `bfloat16` - will be included in a future version of the standard._ 5. The following topics are out of scope: I/O, polynomials, error handling, testing routines, building and packaging related functionality, methods of From 5a145340fbe17b23aee4c7f2e5d753c64a454443 Mon Sep 17 00:00:00 2001 From: Athan Date: Sat, 2 Dec 2023 08:36:50 -0800 Subject: [PATCH 464/551] Add `signbit` specification for determining whether a sign bit is set (#705) --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 8048eb38a..b3f08727b 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -69,6 +69,7 @@ Objects in API remainder round sign + signbit sin sinh square diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index e3988a09f..5ff0c45d6 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -51,6 +51,7 @@ "remainder", "round", "sign", + "signbit", "sin", "sinh", "square", @@ -2215,6 +2216,40 @@ def sign(x: array, /) -> array: """ +def signbit(x: array, /) -> array: + r""" + Determines whether the sign bit is set for each element ``x_i`` of the input array ``x``. + + The sign bit of a real-valued floating-point number ``x_i`` is set whenever ``x_i`` is either ``-0``, less than zero, or a signed ``NaN`` (i.e., a ``NaN`` value whose sign bit is ``1``). + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``+0``, the result is ``False``. + - If ``x_i`` is ``-0``, the result is ``True``. + - If ``x_i`` is ``+infinity``, the result is ``False``. + - If ``x_i`` is ``-infinity``, the result is ``True``. + - If ``x_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``False``. + - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + """ + + def sin(x: array, /) -> array: r""" Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. From 1fd3429eb1bfe3a62875404e4e5e45d01873dd3f Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 13 Dec 2023 21:01:22 -0800 Subject: [PATCH 465/551] Add specification for computing the cumulative sum PR-URL: https://github.com/data-apis/array-api/pull/653 --- .../statistical_functions.rst | 1 + .../_draft/statistical_functions.py | 60 ++++++++++++++++++- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/statistical_functions.rst b/spec/draft/API_specification/statistical_functions.rst index 23cd2cb1d..20e02b3f9 100644 --- a/spec/draft/API_specification/statistical_functions.rst +++ b/spec/draft/API_specification/statistical_functions.rst @@ -18,6 +18,7 @@ Objects in API :toctree: generated :template: method.rst + cumulative_sum max mean min diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 92cdb5755..14952402c 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -1,9 +1,67 @@ -__all__ = ["max", "mean", "min", "prod", "std", "sum", "var"] +__all__ = ["cumulative_sum", "max", "mean", "min", "prod", "std", "sum", "var"] from ._types import Optional, Tuple, Union, array, dtype +def cumulative_sum( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative sum of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum 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. + dtype: Optional[dtype] + data type of the returned array. If ``None``, + + - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. + + - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, + + - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. + - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + + .. note:: + keyword argument is intended to help prevent data type overflows. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative sum. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative sum must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + """ + + def max( x: array, /, From bda9c4872f65d5420142d65269968e287bcc9d59 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 13 Dec 2023 21:06:13 -0800 Subject: [PATCH 466/551] Add note clarifying behavior for out-of-bounds indices in `take` PR-URL: https://github.com/data-apis/array-api/pull/701 --- src/array_api_stubs/_draft/indexing_functions.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 3f4c25215..f3bf0fc14 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -16,6 +16,10 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: input array. indices: array array indices. The array must be one-dimensional and have an integer data type. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + 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 50ca6792b44aa3d10a31c696adbd03f815ffabac Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 13 Dec 2023 21:11:35 -0800 Subject: [PATCH 467/551] Add specifications for `maximum` and `minimum` Closes: https://github.com/data-apis/array-api/issues/667 PR-URL: https://github.com/data-apis/array-api/pull/713 --- .../elementwise_functions.rst | 2 + .../_draft/elementwise_functions.py | 62 +++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index b3f08727b..7984d8e02 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -60,6 +60,8 @@ Objects in API logical_not logical_or logical_xor + maximum + minimum multiply negative not_equal diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 5ff0c45d6..3da5412ca 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -42,6 +42,8 @@ "logical_not", "logical_or", "logical_xor", + "maximum", + "minimum", "multiply", "negative", "not_equal", @@ -1820,6 +1822,66 @@ def logical_xor(x1: array, x2: array, /) -> array: """ +def maximum(x1: array, x2: array, /) -> array: + r""" + Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise maximum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + """ + + +def minimum(x1: array, x2: array, /) -> array: + r""" + Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise minimum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + """ + + def multiply(x1: array, x2: array, /) -> array: r""" Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. From 5c2423a96c9fd5113e405df88f2422f14cd978b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Sok=C3=B3=C5=82?= <8431159+mtsokol@users.noreply.github.com> Date: Mon, 18 Dec 2023 21:27:33 +0100 Subject: [PATCH 468/551] Fix definition of complex inner product in `vecdot` (#723) PR-URL: https://github.com/data-apis/array-api/pull/723 Reviewed-by: Athan Reines --- src/array_api_stubs/_2022_12/linear_algebra_functions.py | 4 ++-- src/array_api_stubs/_draft/linear_algebra_functions.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linear_algebra_functions.py b/src/array_api_stubs/_2022_12/linear_algebra_functions.py index 110a19ce1..d5329db76 100644 --- a/src/array_api_stubs/_2022_12/linear_algebra_functions.py +++ b/src/array_api_stubs/_2022_12/linear_algebra_functions.py @@ -122,9 +122,9 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as .. math:: - \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} a_i\overline{b_i} + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i - over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{b_i}` denotes the complex conjugate if :math:`b_i` is complex and the identity if :math:`b_i` is real-valued. + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. Parameters ---------- diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index 079a90ee6..96f082bd5 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -126,9 +126,9 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as .. math:: - \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} a_i\overline{b_i} + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i - over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{b_i}` denotes the complex conjugate if :math:`b_i` is complex and the identity if :math:`b_i` is real-valued. + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. Parameters ---------- From 72f86f37e51cd28183c6b25c6b0b6d81ff497856 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 11 Jan 2024 13:47:26 -0800 Subject: [PATCH 469/551] Add `searchsorted` to the specification (#699) --- .../API_specification/searching_functions.rst | 1 + .../_draft/searching_functions.py | 54 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/spec/draft/API_specification/searching_functions.rst b/spec/draft/API_specification/searching_functions.rst index 01ab4e82a..c952f1aad 100644 --- a/spec/draft/API_specification/searching_functions.rst +++ b/spec/draft/API_specification/searching_functions.rst @@ -23,4 +23,5 @@ Objects in API argmax argmin nonzero + searchsorted where diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index e586a7656..dda000e74 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -1,7 +1,7 @@ -__all__ = ["argmax", "argmin", "nonzero", "where"] +__all__ = ["argmax", "argmin", "nonzero", "searchsorted", "where"] -from ._types import Optional, Tuple, array +from ._types import Optional, Tuple, Literal, array def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: @@ -87,6 +87,56 @@ def nonzero(x: array, /) -> Tuple[array, ...]: """ +def searchsorted( + x1: array, + x2: array, + /, + *, + side: Literal["left", "right"] = "left", + sorter: Optional[array] = None, +) -> array: + """ + Finds the indices into ``x1`` such that, if the corresponding elements in ``x2`` were inserted before the indices, the order of ``x1``, when sorted in ascending order, would be preserved. + + Parameters + ---------- + x1: array + input array. Must be a one-dimensional array. Should have a real-valued data type. If ``sorter`` is ``None``, must be sorted in ascending order; otherwise, ``sorter`` must be an array of indices that sort ``x1`` in ascending order. + x2: array + array containing search values. Should have a real-valued data type. + side: Literal['left', 'right'] + argument controlling which index is returned if a value lands exactly on an edge. + + Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + + If ``side == 'left'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``0``. + + Otherwise, if ``side == 'right'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + + Default: ``'left'``. + sorter: Optional[array] + array of indices that sort ``x1`` in ascending order. The array must have the same shape as ``x1`` and have an integer data type. Default: ``None``. + + Returns + ------- + out: array + an array of indices with the same shape as ``x2``. The returned array must have the default array index data type. + + Notes + ----- + + For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. + + While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + """ + + def where(condition: array, x1: array, x2: array, /) -> array: """ Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. From 8fe8b0864ce0dd48cca1006accb684c34513783d Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 11 Jan 2024 23:26:14 +0100 Subject: [PATCH 470/551] Fix sidebar contents under Extensions (#729) The problem was that the sidebar doesn't show the named pages in the toctree if that toctree is under a subheading in index.rst Closes gh-716 --- spec/draft/extensions/index.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/draft/extensions/index.rst b/spec/draft/extensions/index.rst index 30d9cfa90..3b9409954 100644 --- a/spec/draft/extensions/index.rst +++ b/spec/draft/extensions/index.rst @@ -24,11 +24,10 @@ the implementer, e.g. via a regular submodule that is imported under the The functions in an extension must adhere to the same conventions as those in the array API standard. See :ref:`api-specification`. - -Extensions ----------- +------------------------------------------------------------------------------ .. toctree:: + :caption: Extension modules: :maxdepth: 1 fourier_transform_functions From 7a56675105864d98cf43b65656f6c2edf93bd2d4 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 12 Jan 2024 10:41:22 +0100 Subject: [PATCH 471/551] Update DLPack content to address unsupported use cases (#709) Also extend the description of errors when DLPack cannot be supported --- spec/draft/design_topics/data_interchange.rst | 19 +++++++++++++++++++ .../_draft/creation_functions.py | 14 ++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/spec/draft/design_topics/data_interchange.rst b/spec/draft/design_topics/data_interchange.rst index 8686042c8..3b3040672 100644 --- a/spec/draft/design_topics/data_interchange.rst +++ b/spec/draft/design_topics/data_interchange.rst @@ -84,3 +84,22 @@ page gives a high-level specification for data exchange in Python using DLPack. are recommended to do so using the same syntax and semantics as outlined below. They are not required to return an array object from ``from_dlpack`` which conforms to this standard. + +Non-supported use cases +----------------------- + +Use of DLPack requires that the data can be represented by a strided, in-memory +layout on a single device. This covers usage by a large range of, but not all, +known and possible array libraries. Use cases that are not supported by DLPack +include: + +- Distributed arrays, i.e., the data residing on multiple nodes or devices, +- Sparse arrays, i.e., sparse representations where a data value (typically + zero) is implicit. + +There may be other reasons why it is not possible or desirable for an +implementation to materialize the array as strided data in memory. In such +cases, the implementation may raise a `BufferError` in the `__dlpack__` or +`__dlpack_device__` method. In case an implementation is never able to export +its array data via DLPack, it may omit `__dlpack__` and `__dlpack_device__` +completely, and hence `from_dlpack` may raise an `AttributeError`. diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 5e2bb44e6..69733a646 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -232,6 +232,20 @@ def from_dlpack(x: object, /) -> array: :class: note The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array + may raise ``BufferError`` when the data cannot be exported as DLPack + (e.g., incompatible dtype or strides). It may also raise other errors + when export fails for other reasons (e.g., not enough memory available + to materialize the data). ``from_dlpack`` must propagate such + exceptions. + AttributeError + If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present + on the input array. This may happen for libraries that are never able + to export their data with DLPack. """ From 6e320d01b60dc38e7119ed3e9d409a00818bbe0b Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 22 Jan 2024 12:07:38 -0800 Subject: [PATCH 472/551] Add `clip` to the specification PR-URL: https://github.com/data-apis/array-api/pull/715 --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 35 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 7984d8e02..f0b69cfcb 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -33,6 +33,7 @@ Objects in API bitwise_right_shift bitwise_xor ceil + clip conj copysign cos diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 3da5412ca..c71b6674b 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -15,6 +15,7 @@ "bitwise_right_shift", "bitwise_xor", "ceil", + "clip", "conj", "copysign", "cos", @@ -65,7 +66,7 @@ ] -from ._types import array +from ._types import Optional, Union, array def abs(x: array, /) -> array: @@ -775,6 +776,38 @@ def ceil(x: array, /) -> array: """ +def clip( + x: array, + /, + min: Optional[Union[int, float, array]] = None, + max: Optional[Union[int, float, array]] = None, +) -> array: + r""" + Clamps each element ``x_i`` of the input array ``x`` to the range ``[min, max]``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + min: Optional[Union[int, float, array]] + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + max: Optional[Union[int, float, array]] + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + + Returns + ------- + out: array + an array containing element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. + - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + """ + + def conj(x: array, /) -> array: """ Returns the complex conjugate for each element ``x_i`` of the input array ``x``. From 0cde841671d99fc2e028eea87cd13d6eea49704e Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 22 Jan 2024 21:30:09 +0100 Subject: [PATCH 473/551] Clarify guidance in the "function and method signatures" section The type annotations part was a little outdated. For the positional and keyword-only descriptions, improve the language to account for exceptions to the default design rules. Closes: #475 PR-URL: https://github.com/data-apis/array-api/pull/730 Reviewed-by: Athan Reines --- .../function_and_method_signatures.rst | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/spec/draft/API_specification/function_and_method_signatures.rst b/spec/draft/API_specification/function_and_method_signatures.rst index 86d0819a6..0eca2ac69 100644 --- a/spec/draft/API_specification/function_and_method_signatures.rst +++ b/spec/draft/API_specification/function_and_method_signatures.rst @@ -5,7 +5,7 @@ Function and method signatures Function signatures in this standard adhere to the following: -1. Positional parameters must be `positional-only `_ parameters. +1. Positional parameters should 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. @@ -20,7 +20,7 @@ Function signatures in this standard adhere to the following: namespace >= 3.8. Alternatively, they can add guidance to their users in the documentation to use the functions as if they were positional-only. -2. Optional parameters must be `keyword-only `_ arguments. +2. Optional parameters should be `keyword-only `_ arguments. *Rationale: this leads to more readable code, and it makes it easier to evolve an API over time by adding keywords without having to worry about @@ -30,8 +30,8 @@ Function signatures in this standard adhere to the following: is called ``x``. For functions that have multiple array parameters, those parameters are called ``xi`` with ``i = 1, 2, ...`` (i.e., ``x1``, ``x2``). -4. Type annotations are left out of the signatures themselves for readability; however, - they are added to individual parameter descriptions. For code which aims to +4. Signatures include type annotations. The type annotations are also added to + individual parameter and return value descriptions. For code which aims to adhere to the standard, adding type annotations is strongly recommended. A function signature and description will look like: @@ -57,3 +57,7 @@ A function signature and description will look like: Method signatures will follow the same conventions modulo the addition of ``self``. + +Note that there are a few exceptions to rules (1) and (2), in cases where +it enhances readability or use of the non-default form of the parameter in +question is commonly used in code written for existing array libraries. From 293512d35f8acccb55b184462505cdb1ab5d1a14 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Mon, 22 Jan 2024 23:22:28 +0100 Subject: [PATCH 474/551] Upgrade Sphinx version used in doc deployment (#735) * Upgrade Sphinx version used in doc deployment It was breaking with: ``` sphinx-build "spec/2021.12" "_site/2021.12" -W --keep-going Running Sphinx v4.3.0 Sphinx version error: The sphinxcontrib.applehelp extension used by this project needs at least Sphinx v5.0; it therefore cannot be built with this version. ``` * Fix some doc build warnings that broke in CI --- doc-requirements.txt | 3 +-- spec/2021.12/assumptions.md | 4 ++-- spec/2021.12/purpose_and_scope.md | 2 +- spec/2021.12/use_cases.md | 2 +- spec/2022.12/assumptions.md | 4 ++-- spec/2022.12/purpose_and_scope.md | 2 +- spec/2022.12/use_cases.md | 2 +- spec/draft/assumptions.md | 4 ++-- spec/draft/purpose_and_scope.md | 2 +- spec/draft/use_cases.md | 2 +- src/_array_api_conf.py | 2 ++ 11 files changed, 15 insertions(+), 14 deletions(-) diff --git a/doc-requirements.txt b/doc-requirements.txt index 488aa3e81..08ced9aa2 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -1,8 +1,7 @@ -sphinx==4.3.0 +sphinx==6.2.1 sphinx-material==0.0.30 myst-parser sphinx_markdown_tables sphinx_copybutton sphinx_favicon -docutils<0.18 sphinx-math-dollar diff --git a/spec/2021.12/assumptions.md b/spec/2021.12/assumptions.md index 3a90710ea..b11482c5a 100644 --- a/spec/2021.12/assumptions.md +++ b/spec/2021.12/assumptions.md @@ -26,7 +26,7 @@ of functions to be predictable from input dtypes only rather than input values. The only dependency that's assumed in this standard is that on Python itself. Python >= 3.8 is assumed, motivated by the use of positional-only parameters -(see [function and method signatures](API_specification/function_and_method_signatures.md)). +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). Importantly, array libraries are not assumed to be aware of each other, or of a common array-specific layer. The [use cases](use_cases.md) do not require @@ -39,7 +39,7 @@ for that is: Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared -memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.md)). +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). This can be done without a dependency though - only adherence to a protocol is enough. diff --git a/spec/2021.12/purpose_and_scope.md b/spec/2021.12/purpose_and_scope.md index 4678ba064..0debbc08a 100644 --- a/spec/2021.12/purpose_and_scope.md +++ b/spec/2021.12/purpose_and_scope.md @@ -151,7 +151,7 @@ standard is shown in this diagram: _Rationale: this is an important topic for some array-consuming libraries, but there is no widely shared C/Cython API and hence it doesn't make sense at this point in time to standardize anything. See - the [C API section](design_topics/C_API.md) for more details._ + the [C API section](design_topics/C_API.rst) for more details._ 4. Standardization of these dtypes is out of scope: bfloat16, complex, extended precision floating point, datetime, string, object and void dtypes. diff --git a/spec/2021.12/use_cases.md b/spec/2021.12/use_cases.md index 26f7a529c..e24aa50db 100644 --- a/spec/2021.12/use_cases.md +++ b/spec/2021.12/use_cases.md @@ -59,7 +59,7 @@ array implementation as a dependency. It's clear that SciPy functionality that relies on compiled extensions (C, C++, Cython, Fortran) directly can't easily be run on another array library -than NumPy (see [C API](design_topics/C_API.md) for more details about this topic). Pure Python +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python code can work though. There's two main possibilities: 1. Testing with another package, manually or in CI, and simply provide a list diff --git a/spec/2022.12/assumptions.md b/spec/2022.12/assumptions.md index 3a90710ea..b11482c5a 100644 --- a/spec/2022.12/assumptions.md +++ b/spec/2022.12/assumptions.md @@ -26,7 +26,7 @@ of functions to be predictable from input dtypes only rather than input values. The only dependency that's assumed in this standard is that on Python itself. Python >= 3.8 is assumed, motivated by the use of positional-only parameters -(see [function and method signatures](API_specification/function_and_method_signatures.md)). +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). Importantly, array libraries are not assumed to be aware of each other, or of a common array-specific layer. The [use cases](use_cases.md) do not require @@ -39,7 +39,7 @@ for that is: Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared -memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.md)). +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). This can be done without a dependency though - only adherence to a protocol is enough. diff --git a/spec/2022.12/purpose_and_scope.md b/spec/2022.12/purpose_and_scope.md index 38287f270..f375c9512 100644 --- a/spec/2022.12/purpose_and_scope.md +++ b/spec/2022.12/purpose_and_scope.md @@ -151,7 +151,7 @@ standard is shown in this diagram: _Rationale: this is an important topic for some array-consuming libraries, but there is no widely shared C/Cython API and hence it doesn't make sense at this point in time to standardize anything. See - the [C API section](design_topics/C_API.md) for more details._ + the [C API section](design_topics/C_API.rst) for more details._ 4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. diff --git a/spec/2022.12/use_cases.md b/spec/2022.12/use_cases.md index 26f7a529c..e24aa50db 100644 --- a/spec/2022.12/use_cases.md +++ b/spec/2022.12/use_cases.md @@ -59,7 +59,7 @@ array implementation as a dependency. It's clear that SciPy functionality that relies on compiled extensions (C, C++, Cython, Fortran) directly can't easily be run on another array library -than NumPy (see [C API](design_topics/C_API.md) for more details about this topic). Pure Python +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python code can work though. There's two main possibilities: 1. Testing with another package, manually or in CI, and simply provide a list diff --git a/spec/draft/assumptions.md b/spec/draft/assumptions.md index 3a90710ea..b11482c5a 100644 --- a/spec/draft/assumptions.md +++ b/spec/draft/assumptions.md @@ -26,7 +26,7 @@ of functions to be predictable from input dtypes only rather than input values. The only dependency that's assumed in this standard is that on Python itself. Python >= 3.8 is assumed, motivated by the use of positional-only parameters -(see [function and method signatures](API_specification/function_and_method_signatures.md)). +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). Importantly, array libraries are not assumed to be aware of each other, or of a common array-specific layer. The [use cases](use_cases.md) do not require @@ -39,7 +39,7 @@ for that is: Array libraries may know how to interoperate with each other, for example by constructing their own array type from that of another library or by shared -memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.md)). +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). This can be done without a dependency though - only adherence to a protocol is enough. diff --git a/spec/draft/purpose_and_scope.md b/spec/draft/purpose_and_scope.md index 38287f270..f375c9512 100644 --- a/spec/draft/purpose_and_scope.md +++ b/spec/draft/purpose_and_scope.md @@ -151,7 +151,7 @@ standard is shown in this diagram: _Rationale: this is an important topic for some array-consuming libraries, but there is no widely shared C/Cython API and hence it doesn't make sense at this point in time to standardize anything. See - the [C API section](design_topics/C_API.md) for more details._ + the [C API section](design_topics/C_API.rst) for more details._ 4. Standardization of these dtypes is out of scope: bfloat16, extended precision floating point, datetime, string, object and void dtypes. diff --git a/spec/draft/use_cases.md b/spec/draft/use_cases.md index 26f7a529c..e24aa50db 100644 --- a/spec/draft/use_cases.md +++ b/spec/draft/use_cases.md @@ -59,7 +59,7 @@ array implementation as a dependency. It's clear that SciPy functionality that relies on compiled extensions (C, C++, Cython, Fortran) directly can't easily be run on another array library -than NumPy (see [C API](design_topics/C_API.md) for more details about this topic). Pure Python +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python code can work though. There's two main possibilities: 1. Testing with another package, manually or in CI, and simply provide a list diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index d3a136eaa..9c5722f94 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -52,12 +52,14 @@ nitpick_ignore = [ ("py:class", "collections.abc.Sequence"), ("py:class", "Optional[Union[int, float, Literal[inf, - inf, 'fro', 'nuc']]]"), + ("py:class", "int | float | ~typing.Literal[inf, -inf, 'fro', 'nuc'] | None"), ("py:class", "Union[int, float, Literal[inf, - inf]]"), ( "py:obj", "typing.Optional[typing.Union[int, float, typing.Literal[inf, - inf, 'fro', 'nuc']]]", ), ("py:obj", "typing.Union[int, float, typing.Literal[inf, - inf]]"), + ("py:class", "int | float | ~typing.Literal[inf, -inf]"), ("py:class", "enum.Enum"), ("py:class", "ellipsis"), ] From 95332bb71159cea68e15e7d20364a3e07060a402 Mon Sep 17 00:00:00 2001 From: Hameer Abbasi <2190658+hameerabbasi@users.noreply.github.com> Date: Thu, 25 Jan 2024 13:59:59 +0100 Subject: [PATCH 475/551] Fix wording for comparison operators PR-URL: https://github.com/data-apis/array-api/pull/736 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- spec/2022.12/API_specification/array_object.rst | 3 ++- spec/draft/API_specification/array_object.rst | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/spec/2022.12/API_specification/array_object.rst b/spec/2022.12/API_specification/array_object.rst index b15bbdc43..45aec9b34 100644 --- a/spec/2022.12/API_specification/array_object.rst +++ b/spec/2022.12/API_specification/array_object.rst @@ -163,7 +163,8 @@ A conforming implementation of the array API standard must provide and support a - `operator.ne(x1, x2) `_ - `operator.__ne__(x1, x2) `_ -Comparison operators should be defined for arrays having any data type. +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). In-place Operators ~~~~~~~~~~~~~~~~~~ diff --git a/spec/draft/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst index 0fadf9fc5..f8a586ade 100644 --- a/spec/draft/API_specification/array_object.rst +++ b/spec/draft/API_specification/array_object.rst @@ -163,7 +163,8 @@ A conforming implementation of the array API standard must provide and support a - `operator.ne(x1, x2) `_ - `operator.__ne__(x1, x2) `_ -Comparison operators should be defined for arrays having any data type. +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). In-place Operators ~~~~~~~~~~~~~~~~~~ From 937d3b8e22ef42d2420a951cefe6ec28107f31bf Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 8 Feb 2024 06:14:02 -0700 Subject: [PATCH 476/551] Clarify specification guidance in FFT functions PR-URL: https://github.com/data-apis/array-api/pull/720 Closes: https://github.com/data-apis/array-api/issues/717 Closes: https://github.com/data-apis/array-api/issues/718 Ref: https://github.com/data-apis/array-api/pull/189 Co-authored-by: Leo Fang Co-authored-by: Athan Reines Reviewed-by: Leo Fang Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2022_12/fft.py | 297 +++++++++++++--------------- src/array_api_stubs/_draft/fft.py | 262 +++++++++++------------- 2 files changed, 253 insertions(+), 306 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index 7979095fe..f79aa155e 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -1,3 +1,20 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + from ._types import Tuple, Union, Sequence, array, Optional, Literal, device @@ -13,24 +30,22 @@ def fft( Computes the one-dimensional discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -43,7 +58,7 @@ def fft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -64,24 +79,22 @@ def ifft( Computes the one-dimensional inverse discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -94,7 +107,7 @@ def ifft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -107,8 +120,8 @@ def fftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -120,24 +133,19 @@ def fftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -152,7 +160,7 @@ def fftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -165,8 +173,8 @@ def ifftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -178,24 +186,19 @@ def ifftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -210,7 +213,7 @@ def ifftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -231,24 +234,22 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -261,7 +262,7 @@ def rfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -282,24 +283,22 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Should have a complex-valued floating-point data type. - n: int - length of the transformed axis of the **output**. If + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -312,11 +311,13 @@ def irfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + .. versionadded:: 2022.12 """ @@ -325,8 +326,8 @@ def rfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -339,23 +340,18 @@ def rfftn( ---------- x: array input array. Must have a real-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **input**. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -370,7 +366,7 @@ def rfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. Notes ----- @@ -383,8 +379,8 @@ def irfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -397,23 +393,18 @@ def irfftn( ---------- x: array input array. Should have a complex-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **output**. ``n=s[i]`` is also the number of input points used along the axis (dimension) ``i``, except for the last axis, where ``n=s[-1]//2+1`` points of the input are used. If + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - - ``n`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``n``. - - ``n`` is less than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``n``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array, except for the last axis which is trimmed to ``2*(m-1)``, where ``m`` is the length of the input along the axis. + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. - - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. - - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -428,11 +419,13 @@ def irfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. Notes ----- + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + .. versionadded:: 2022.12 """ @@ -451,19 +444,17 @@ def hfft( Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the **output**. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -476,7 +467,7 @@ def hfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -500,18 +491,16 @@ def ihfft( ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -524,7 +513,7 @@ def ihfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -535,9 +524,9 @@ def ihfft( def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies. + Computes the discrete Fourier transform sample frequencies. - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -556,7 +545,7 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar Returns ------- out: array - an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -567,9 +556,9 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -590,7 +579,7 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a Returns ------- out: array - an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -599,9 +588,9 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a """ -def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: """ - Shift the zero-frequency component to the center of the spectrum. + Shifts the zero-frequency component to the center of the spectrum. This function swaps half-spaces for all axes (dimensions) specified by ``axes``. @@ -612,13 +601,13 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- @@ -627,7 +616,9 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: """ -def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: """ Inverse of ``fftshift``. @@ -638,34 +629,16 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- .. versionadded:: 2022.12 """ - - -__all__ = [ - "fft", - "ifft", - "fftn", - "ifftn", - "rfft", - "irfft", - "rfftn", - "irfftn", - "hfft", - "ihfft", - "fftfreq", - "rfftfreq", - "fftshift", - "ifftshift", -] diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 4a59392d5..f79aa155e 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -30,24 +30,22 @@ def fft( Computes the one-dimensional discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -60,7 +58,7 @@ def fft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -81,24 +79,22 @@ def ifft( Computes the one-dimensional inverse discrete Fourier transform. .. note:: - Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same (length, axis, and normalization mode). + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the output. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -111,7 +107,7 @@ def ifft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -124,8 +120,8 @@ def fftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -137,24 +133,19 @@ def fftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -169,7 +160,7 @@ def fftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -182,8 +173,8 @@ def ifftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -195,24 +186,19 @@ def ifftn( Parameters ---------- x: array - input array. Should have a floating-point data type. - s: Sequence[int] - size of each transformed axis of the output. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -227,7 +213,7 @@ def ifftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. Notes ----- @@ -248,24 +234,22 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -278,7 +262,7 @@ def rfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -299,24 +283,22 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent length. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- x: array input array. Should have a complex-valued floating-point data type. - n: int - length of the transformed axis of the **output**. If + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the inverse Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -329,11 +311,13 @@ def irfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the transformed axis is ``n`` (if given) or ``2*(m-1)`` (otherwise). + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + .. versionadded:: 2022.12 """ @@ -342,8 +326,8 @@ def rfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -356,23 +340,18 @@ def rfftn( ---------- x: array input array. Must have a real-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **input**. If - - - ``s[i]`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``s[i]``. - - ``s[i]`` is less than the size of the input array along a corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``s[i]``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. - - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -387,7 +366,7 @@ def rfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. Notes ----- @@ -400,8 +379,8 @@ def irfftn( x: array, /, *, - s: Sequence[int] = None, - axes: Sequence[int] = None, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, norm: Literal["backward", "ortho", "forward"] = "backward", ) -> array: """ @@ -414,23 +393,18 @@ def irfftn( ---------- x: array input array. Should have a complex-valued floating-point data type. - s: Sequence[int] - size of each transformed axis of the **output**. ``n=s[i]`` is also the number of input points used along the axis (dimension) ``i``, except for the last axis, where ``n=s[-1]//2+1`` points of the input are used. If - - - ``n`` is greater than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is zero-padded to size ``n``. - - ``n`` is less than the size of the input array along the corresponding axis (dimension) ``i``, the input array along the axis ``i`` is trimmed to size ``n``. - - ``s[i]`` is ``-1``, the whole input array along the axis ``i`` is used (no padding/trimming). - - ``s`` is not provided, the size of each transformed axis (dimension) in the output array must equal the size of the corresponding axis in the input array, except for the last axis which is trimmed to ``2*(m-1)``, where ``m`` is the length of the input along the axis. - - If ``s`` is not ``None``, ``axes`` must not be ``None`` either, and ``s[i]`` corresponds to the size along the transformed axis specified by ``axes[i]``. + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - Default: ``None``. - axes: Sequence[int] - axes (dimensions) over which to compute the Fourier transform. If ``None``, all axes must be transformed. + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. - If ``s`` is specified, the corresponding ``axes`` to be transformed must be explicitly specified too. + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -445,11 +419,13 @@ def irfftn( Returns ------- out: array - an array transformed along the axes (dimension) indicated by ``axes``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. The length along the last transformed axis is ``s[-1]`` (if given) or ``2*(m - 1)`` (otherwise), and all other axes ``s[i]``. + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. Notes ----- + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + .. versionadded:: 2022.12 """ @@ -468,19 +444,17 @@ def hfft( Parameters ---------- x: array - input array. Should have a floating-point data type. - n: int - length of the transformed axis of the **output**. If + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. - - ``n//2+1`` is greater than the length of the input array, the input array is zero-padded to length ``n//2+1``. - - ``n//2+1`` is less than the length of the input array, the input array is trimmed to length ``n//2+1``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length ``2*(m-1)``, where ``m`` is the length of the input along the axis specified by ``axis``. + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -493,7 +467,7 @@ def hfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. Notes ----- @@ -517,18 +491,16 @@ def ihfft( ---------- x: array input array. Must have a real-valued floating-point data type. - n: int - length of the transformed axis of the **input**. If + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. - - ``n`` is greater than the length of the input array, the input array is zero-padded to length ``n``. - - ``n`` is less than the length of the input array, the input array is trimmed to length ``n``. - - ``n`` is not provided, the length of the transformed axis of the output must equal the length of the input along the axis specified by ``axis``. + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. Default: ``None``. axis: int - axis (dimension) over which to compute the Fourier transform. If not set, the last axis (dimension) is used. - - Default: ``-1``. + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -541,7 +513,7 @@ def ihfft( Returns ------- out: array - an array transformed along the axis (dimension) indicated by ``axis``. The returned array must have a complex-valued floating-point data type determined by :ref:`type-promotion`. + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. Notes ----- @@ -552,9 +524,9 @@ def ihfft( def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies. + Computes the discrete Fourier transform sample frequencies. - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -573,7 +545,7 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar Returns ------- out: array - an array of length ``n`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -584,9 +556,9 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: """ - Returns the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). - For a Fourier transform of length ``n`` and length unit of ``d`` the frequencies are described as: + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: .. code-block:: @@ -607,7 +579,7 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a Returns ------- out: array - an array of length ``n//2+1`` containing the sample frequencies. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. Notes ----- @@ -616,9 +588,9 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a """ -def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: """ - Shift the zero-frequency component to the center of the spectrum. + Shifts the zero-frequency component to the center of the spectrum. This function swaps half-spaces for all axes (dimensions) specified by ``axes``. @@ -629,13 +601,13 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- @@ -644,7 +616,9 @@ def fftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: """ -def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: """ Inverse of ``fftshift``. @@ -655,13 +629,13 @@ def ifftshift(x: array, /, *, axes: Union[int, Sequence[int]] = None) -> array: ---------- x: array input array. Should have a floating-point data type. - axes: Union[int, Sequence[int]] + axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. Returns ------- out: array - the shifted array. The returned array must have the same data type as ``x``. + the shifted array. The returned array must have the same data type and shape as ``x``. Notes ----- From 425e9eb4eeeaf9057b5f2e93168ff377ddb9775f Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Thu, 8 Feb 2024 16:17:52 -0500 Subject: [PATCH 477/551] Fix typo in FFT guidance PR-URL: https://github.com/data-apis/array-api/pull/743 Reviewed-by: Athan Reines Ref: https://github.com/data-apis/array-api/pull/720 --- src/array_api_stubs/_2022_12/fft.py | 4 ++-- src/array_api_stubs/_draft/fft.py | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index f79aa155e..901b8407b 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -234,7 +234,7 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- @@ -283,7 +283,7 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index f79aa155e..901b8407b 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -234,7 +234,7 @@ def rfft( Computes the one-dimensional discrete Fourier transform for real-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- @@ -283,7 +283,7 @@ def irfft( Computes the one-dimensional inverse of ``rfft`` for complex-valued input. .. note:: - Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and and normalization mode) and consistent values for the number of elements over which to compute the transforms. + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. Parameters ---------- From 83420d21394e92b2fc92313f789f7b3d8c0c8c93 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 9 Feb 2024 01:23:41 +0100 Subject: [PATCH 478/551] Add versioning support to DLPack APIs (#602) * Add versioning support to DLPack APIs xref https://github.com/dmlc/dlpack/issues/116 * Address review comment, replace ">=2 years" by "from March 2025" * nit: re-order * improvements & fixes * Satisfy linter * Satisfy linter * Update src/array_api_stubs/_draft/array_object.py Co-authored-by: Sebastian Berg --------- Co-authored-by: Leo Fang Co-authored-by: Athan Co-authored-by: Sebastian Berg --- src/array_api_stubs/_draft/array_object.py | 102 +++++++++++++----- .../_draft/creation_functions.py | 5 + 2 files changed, 83 insertions(+), 24 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 600e947e0..9f8be2479 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -288,7 +288,11 @@ def __complex__(self: array, /) -> complex: """ def __dlpack__( - self: array, /, *, stream: Optional[Union[int, Any]] = None + self: array, + /, + *, + stream: Optional[Union[int, Any]] = None, + max_version: Optional[tuple[int, int]] = None, ) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -298,20 +302,14 @@ def __dlpack__( self: array array instance. stream: Optional[Union[int, Any]] - for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be a positive integer or ``-1``. If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. - - For other device types which do have a stream, queue or similar synchronization mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. - - - .. note:: - Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be an integer larger than or equal to ``-1`` (see below for allowed values on each platform). If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. + For other device types which do have a stream, queue, or similar synchronization/ordering mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. - Device-specific notes: + .. note:: + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. - - .. admonition:: CUDA - :class: note + Device-specific values of ``stream`` for CUDA: - ``None``: producer must assume the legacy default stream (default). - ``1``: the legacy default stream. @@ -319,24 +317,28 @@ def __dlpack__( - ``> 2``: stream number represented as a Python integer. - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. - - .. admonition:: ROCm - :class: note + Device-specific values of ``stream`` for ROCm: - ``None``: producer must assume the legacy default stream (default). - ``0``: the default stream. - ``> 2``: stream number represented as a Python integer. - Using ``1`` and ``2`` is not supported. - - .. admonition:: Tip - :class: important - - It is recommended that implementers explicitly handle streams. If - they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` - (ROCm) is preferred. ``None`` is a safe default for developers who do - not want to think about stream handling at all, potentially at the - cost of more synchronization than necessary. + .. admonition:: Tip + :class: important + + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronizations than necessary. + max_version: Optional[tuple[int, int]] + The maximum DLPack version that the *consumer* (i.e., the caller of + ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. + This method may return a capsule of version ``max_version`` (recommended + if it does support that), or of a different version. + This means the consumer must verify the version even when + `max_version` is passed. Returns ------- @@ -353,9 +355,61 @@ def __dlpack__( Notes ----- + The DLPack version scheme is SemVer, where the major DLPack versions + represent ABI breaks, and minor versions represent ABI-compatible additions + (e.g., new enum values for new data types or device types). + + The ``max_version`` keyword was introduced in v2023.12, and goes + together with the ``DLManagedTensorVersioned`` struct added in DLPack + 1.0. This keyword may not be used by consumers until a later time after + introduction, because producers may implement the support at a different + point in time. + + It is recommended for the producer to use this logic in the implementation + of ``__dlpack__``: + + .. code:: python + + if max_version is None: + # Keep and use the DLPack 0.X implementation + # Note: from March 2025 onwards (but ideally as late as + # possible), it's okay to raise BufferError here + else: + # We get to produce `DLManagedTensorVersioned` now. Note that + # our_own_dlpack_version is the max version that the *producer* + # supports and fills in the `DLManagedTensorVersioned::version` + # field + if max_version >= our_own_dlpack_version: + # Consumer understands us, just return a Capsule with our max version + elif max_version[0] == our_own_dlpack_version[0]: + # major versions match, we should still be fine here - + # return our own max version + else: + # if we're at a higher major version internally, did we + # keep an implementation of the older major version around? + # For example, if the producer is on DLPack 1.x and the consumer + # is 0.y, can the producer still export a capsule containing + # DLManagedTensor and not DLManagedTensorVersioned? + # If so, use that. Else, the producer should raise a BufferError + # here to tell users that the consumer's max_version is too + # old to allow the data exchange to happen. + + And this logic for the consumer in ``from_dlpack``: + + .. code:: python + + try: + x.__dlpack__(max_version=(1, 0)) + # if it succeeds, store info from the capsule named "dltensor_versioned", + # and need to set the name to "used_dltensor_versioned" when we're done + except TypeError: + x.__dlpack__() .. versionchanged:: 2022.12 Added BufferError. + + .. versionchanged:: 2023.12 + Added the ``max_version`` keyword. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 69733a646..d0f967717 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -246,6 +246,11 @@ def from_dlpack(x: object, /) -> array: If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present on the input array. This may happen for libraries that are never able to export their data with DLPack. + + Notes + ----- + See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in + order to handle DLPack versioning correctly. """ From a902944642a553b287a226711d380676c070940e Mon Sep 17 00:00:00 2001 From: Athan Date: Fri, 9 Feb 2024 00:17:51 -0800 Subject: [PATCH 479/551] Add note regarding copy behavior when moving to same device (#742) Closes: https://github.com/data-apis/array-api/issues/645 --- src/array_api_stubs/_draft/array_object.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 9f8be2479..5b412685e 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -1140,8 +1140,11 @@ def to_device( an array with the same data and data type as ``self`` and located on the specified ``device``. - .. note:: - If ``stream`` is given, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming library's documentation. + Notes + ----- + + - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. + - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. """ From 2404c9968726f11be30047e903b613fa2031b9e9 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 13 Feb 2024 07:41:16 +0100 Subject: [PATCH 480/551] docs: reorganize data type specification guidance PR-URL: https://github.com/data-apis/array-api/pull/745 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- spec/draft/API_specification/data_types.rst | 198 ++++++++------------ 1 file changed, 78 insertions(+), 120 deletions(-) diff --git a/spec/draft/API_specification/data_types.rst b/spec/draft/API_specification/data_types.rst index a9be88181..5987dd322 100644 --- a/spec/draft/API_specification/data_types.rst +++ b/spec/draft/API_specification/data_types.rst @@ -5,109 +5,83 @@ Data Types Array API specification for supported data types. -A conforming implementation of the array API standard must provide and support the following data types. +A conforming implementation of the array API standard must provide and support +the following data types ("dtypes") in its array object, and as data type +objects in its main namespace under the specified names: + ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| dtype object | description | ++==============+============================================================================================================================================================================================+ +| bool | Boolean (``True`` or ``False``). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int8 | An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int16 | A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int32 | A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int64 | A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint8 | An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint16 | A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint32 | A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint64 | A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float32 | IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float64 | IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex64 | Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex128 | Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Data type objects must have the following methods (no attributes are required): -bool ----- - -Boolean (``True`` or ``False``). - -int8 ----- - -An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. - -int16 ------ - -A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. - -int32 ------ - -A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. - -int64 ------ - -A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. - -uint8 ------ - -An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. - -uint16 ------- - -A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. - -uint32 ------- - -A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. - -uint64 ------- - -A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. - -float32 -------- - -IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). - -float64 -------- +.. + NOTE: please keep the functions in alphabetical order -IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). +.. currentmodule:: array_api.data_types -complex64 ---------- +.. autosummary:: + :toctree: generated + :template: method.rst -Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). + __eq__ -complex128 ----------- -Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). +.. note:: + A conforming implementation of the array API standard may provide and + support additional data types beyond those described in this specification. + It may also support additional methods and attributes on dtype objects. .. note:: IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. -.. note:: - A conforming implementation of the array API standard may provide and support additional data types beyond those described in this specification. - -.. _data-type-objects: -Data Type Objects ------------------ +Use of data type objects +------------------------ -Data types ("dtypes") are objects which are used as ``dtype`` specifiers in functions and methods (e.g., ``zeros((2, 3), dtype=float32)``). +Data type objects are used as ``dtype`` specifiers in functions and methods +(e.g., ``zeros((2, 3), dtype=float32)``), accessible as ``.dtype`` attribute on +arrays, and used in various casting and introspection functions (e.g., +``isdtype(x.dtype, 'integral')``). -.. note:: - A conforming implementation may add additional methods or attributes to data type objects beyond those described in this specification. +``dtype`` keywords in functions specify the data type of arrays returned from +functions or methods. ``dtype`` keywords are not required to affect the data +type used for intermediate calculations or results (e.g., implementors are free +to use a higher-precision data type when accumulating values for reductions, as +long as the returned array has the specified data type). .. note:: Implementations may provide other ways to specify data types (e.g., ``zeros((2, 3), dtype='f4')``) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. -A conforming implementation of the array API standard must provide and support data type objects having the following attributes and methods. - -Methods -~~~~~~~ - -.. - NOTE: please keep the functions in alphabetical order - -.. currentmodule:: array_api.data_types - -.. autosummary:: - :toctree: generated - :template: method.rst - - __eq__ +See :ref:`type-promotion` for specification guidance describing the rules governing the interaction of two or more data types or data type objects. .. _data-type-defaults: @@ -138,6 +112,7 @@ the library should clearly warn about this in its documentation. .. note:: The default data types should be clearly defined in a conforming library's documentation. + .. _data-type-categories: Data Type Categories @@ -145,41 +120,24 @@ Data Type Categories For the purpose of organizing functions within this specification, the following data type categories are defined. -.. note:: - Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. - - -Numeric Data Types -~~~~~~~~~~~~~~~~~~ - -``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. - -Real-valued Data Types -~~~~~~~~~~~~~~~~~~~~~~ - -``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. - -Integer Data Types -~~~~~~~~~~~~~~~~~~ - -``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. - -Floating-point Data Types -~~~~~~~~~~~~~~~~~~~~~~~~~ ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| data type category | dtypes | ++============================+========================================================================================================================================================+ +| Numeric | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Floating-point | ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued floating-point | ``float32`` and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Complex floating-point | ``complex64`` and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Boolean | ``bool``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ -``float32``, ``float64``, ``complex64``, and ``complex128``. -Real-valued Floating-point Data Types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``float32`` and ``float64``. - -Complex Floating-point Data Types -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -``complex64`` and ``complex128``. - -Boolean Data Types -~~~~~~~~~~~~~~~~~~ - -``bool``. +.. note:: + Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. From 72740507b478f014fb65156198534f8046fbe37f Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 13 Feb 2024 09:22:53 +0100 Subject: [PATCH 481/551] feat!: change default promotion behavior in summation APIs This commit modifies type promotion behavior in `sum`, `prod`, `cumulative_sum`, and `linalg.trace` when the input array has a floating-point data type. Previously, the specification required that conforming implementations upcast to the default floating-point data type when the input array data type was of a lower precision. This commit revises that guidance to require conforming libraries return an array having the same data type as the input array. This revision stems from feedback from implementing libraries, where the current status quo matches the changes in this commit, with little desire to change. As such, the specification is amended to match this reality. Closes: https://github.com/data-apis/array-api/issues/731 PR-URL: https://github.com/data-apis/array-api/pull/744 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/linalg.py | 15 ++---- .../_draft/statistical_functions.py | 50 ++++++------------- 2 files changed, 19 insertions(+), 46 deletions(-) diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index d05b53a9f..c66258c7b 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -742,19 +742,12 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr Default: ``0``. dtype: Optional[dtype] - data type of the returned array. If ``None``, + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. - - .. note:: - keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. Returns ------- diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 14952402c..496440535 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -23,22 +23,14 @@ def cumulative_sum( axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum 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. - dtype: Optional[dtype] - data type of the returned array. If ``None``, - - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - .. note:: - keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. include_initial: bool boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. @@ -200,20 +192,14 @@ def prod( input array. Should have a numeric data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. - dtype: Optional[dtype] - data type of the returned array. If ``None``, - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product. Default: ``None``. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - .. note:: - This keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. keepdims: bool if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. @@ -298,20 +284,14 @@ def sum( input array. Should have a numeric data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. - dtype: Optional[dtype] - data type of the returned array. If ``None``, - - if the default data type corresponding to the data type "kind" (integer, real-valued floating-point, or complex floating-point) of ``x`` has a smaller range of values than the data type of ``x`` (e.g., ``x`` has data type ``int64`` and the default data type is ``int32``, or ``x`` has data type ``uint64`` and the default data type is ``int64``), the returned array must have the same data type as ``x``. - - if the default data type corresponding to the data type "kind" of ``x`` has the same or a larger range of values than the data type of ``x``, - - if ``x`` has a real-valued floating-point data type, the returned array must have the default real-valued floating-point data type. - - if ``x`` has a complex floating-point data type, the returned array must have the default complex floating-point data type. - - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. - - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: - If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum. Default: ``None``. + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). - .. note:: - keyword argument is intended to help prevent data type overflows. + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. keepdims: bool if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. From 1745c88764934021a8cb0ac8cd2de43a3cec4a67 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 13 Feb 2024 01:46:11 -0700 Subject: [PATCH 482/551] feat!: restrict `axis` kwarg to negative integers in vecdot and cross This commit updates specification guidance in `vecdot` and `cross` to no longer explicitly support positive `axis` kwarg values. Previous specification guidance conflicts with NumPy gufuncs and restricting to negative integers removes ambiguity in determining over which axis to perform computation. This commit uses `should`, not `must`, to allow conforming libraries to support nonnegative `axis` values for backward compatibility. Closes: #724 Closes: #617 PR-URL: https://github.com/data-apis/array-api/pull/740 Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/linalg.py | 9 ++++----- src/array_api_stubs/_draft/linear_algebra_functions.py | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index c66258c7b..903f928d8 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -83,15 +83,15 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: Parameters ---------- x1: array - first input array. Must have a numeric data type. + first input array. Must have a numeric data type. The size of the axis over which the cross product is to be computed must be equal to 3. x2: array - second input array. Must be compatible with ``x1`` for all non-compute axes (see :ref:`broadcasting`). The size of the axis over which to compute the cross product must be the same size as the respective axis in ``x1``. Must have a numeric data type. + second input array. Must be broadcast compatible with ``x1`` along all axes other than the axis along which the cross-product is computed (see :ref:`broadcasting`). The size of the axis over which the cross product is to be computed must be equal to 3. Must have a numeric data type. .. note:: The compute axis (dimension) must not be broadcasted. axis: int - the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. Returns ------- @@ -110,8 +110,7 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: **Raises** - - if the size of the axis over which to compute the cross product is not equal to ``3``. - - if the size of the axis over which to compute the cross product is not the same (before broadcasting) for both ``x1`` and ``x2``. + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. """ diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index 96f082bd5..eea898a6b 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -141,7 +141,7 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: The contracted axis (dimension) must not be broadcasted. axis: int - axis over which to compute the dot product. Must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting`. If specified as a negative integer, the function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the dot product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. Returns ------- From 474ec2b3eeedc4a6520e63df9601a2e4c6529a5a Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 14 Feb 2024 04:44:52 -0500 Subject: [PATCH 483/551] docs: clarify `s` and `axes` in FFT guidance Closes: https://github.com/data-apis/array-api/issues/747 PR-URL: https://github.com/data-apis/array-api/pull/746 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_2022_12/fft.py | 30 ++++++++++++++++++++--------- src/array_api_stubs/_draft/fft.py | 30 ++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index 901b8407b..bdd7a9c83 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -135,7 +135,7 @@ def fftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -143,9 +143,11 @@ def fftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -188,7 +190,7 @@ def ifftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -196,9 +198,11 @@ def ifftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -341,7 +345,7 @@ def rfftn( x: array input array. Must have a real-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -349,9 +353,11 @@ def rfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -394,7 +400,7 @@ def irfftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. @@ -402,9 +408,11 @@ def irfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -604,6 +612,8 @@ def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) - axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array @@ -632,6 +642,8 @@ def ifftshift( axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 901b8407b..bdd7a9c83 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -135,7 +135,7 @@ def fftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -143,9 +143,11 @@ def fftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -188,7 +190,7 @@ def ifftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -196,9 +198,11 @@ def ifftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] specify the normalization mode. Should be one of the following modes: @@ -341,7 +345,7 @@ def rfftn( x: array input array. Must have a real-valued floating-point data type. s: Optional[Sequence[int]] - number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``. + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. @@ -349,9 +353,11 @@ def rfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -394,7 +400,7 @@ def irfftn( x: array input array. Should have a complex-valued floating-point data type. s: Optional[Sequence[int]] - number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the nth axis specified by ``axes`` and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers, such that, for all ``i``, ``s[i]`` equals ``M[i]``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. @@ -402,9 +408,11 @@ def irfftn( If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. axes: Optional[Sequence[int]] - axes (dimensions) over which to compute the transform. A valid axis must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). - If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. norm: Literal['backward', 'ortho', 'forward'] normalization mode. Should be one of the following modes: @@ -604,6 +612,8 @@ def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) - axes: Optional[Union[int, Sequence[int]]] axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array @@ -632,6 +642,8 @@ def ifftshift( axes: Optional[Union[int, Sequence[int]]] axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + Returns ------- out: array From 71b01c1fbecf7e53fb9f7849b60ba2c2c44a6b73 Mon Sep 17 00:00:00 2001 From: Leo Fang Date: Wed, 14 Feb 2024 15:44:32 -0500 Subject: [PATCH 484/551] Support `copy` and `device` keywords in `from_dlpack` (#741) * support copy in from_dlpack * specify copy stream * allow 3-way copy arg to align all constructors * update to reflect the discussions * clairfy a bit and fix typos * sync the copy docs * clarify what's 'on CPU' * try to make linter happy * remove namespace leak clause, clean up, and add an example * make linter happy * fix Sphinx complaint about Enum * add/update v2023-specific notes on device * remove a note on kDLCPU --------- Co-authored-by: Ralf Gommers --- src/array_api_stubs/_draft/array_object.py | 51 +++++++++++++++++-- .../_draft/creation_functions.py | 46 +++++++++++++++-- 2 files changed, 89 insertions(+), 8 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 5b412685e..5017bf87c 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -293,6 +293,8 @@ def __dlpack__( *, stream: Optional[Union[int, Any]] = None, max_version: Optional[tuple[int, int]] = None, + dl_device: Optional[tuple[Enum, int]] = None, + copy: Optional[bool] = None, ) -> PyCapsule: """ Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. @@ -324,6 +326,12 @@ def __dlpack__( - ``> 2``: stream number represented as a Python integer. - Using ``1`` and ``2`` is not supported. + .. note:: + When ``dl_device`` is provided explicitly, ``stream`` must be a valid + construct for the specified device type. In particular, when ``kDLCPU`` + is in use, ``stream`` must be ``None`` and a synchronization must be + performed to ensure data safety. + .. admonition:: Tip :class: important @@ -333,12 +341,40 @@ def __dlpack__( not want to think about stream handling at all, potentially at the cost of more synchronizations than necessary. max_version: Optional[tuple[int, int]] - The maximum DLPack version that the *consumer* (i.e., the caller of + the maximum DLPack version that the *consumer* (i.e., the caller of ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. This method may return a capsule of version ``max_version`` (recommended if it does support that), or of a different version. This means the consumer must verify the version even when `max_version` is passed. + dl_device: Optional[tuple[enum.Enum, int]] + the DLPack device type. Default is ``None``, meaning the exported capsule + should be on the same device as ``self`` is. When specified, the format + must be a 2-tuple, following that of the return value of :meth:`array.__dlpack_device__`. + If the device type cannot be handled by the producer, this function must + raise ``BufferError``. + + The v2023.12 standard only mandates that a compliant library should offer a way for + ``__dlpack__`` to return a capsule referencing an array whose underlying memory is + accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). + If a copy must be made to enable this support but ``copy`` is set to ``False``, the + function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this + API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the + function must always copy (performed by the producer). If ``False``, the + function must never copy, and raise a ``BufferError`` in case a copy is + deemed necessary (e.g. if a cross-device data movement is requested, and + it is not possible without a copy). If ``None``, the function must reuse + the existing memory buffer if possible and copy otherwise. Default: ``None``. + + When a copy happens, the ``DLPACK_FLAG_BITMASK_IS_COPIED`` flag must be set. + + .. note:: + If a copy happens, and if the consumer-provided ``stream`` and ``dl_device`` + can be understood by the producer, the copy must be performed over ``stream``. Returns ------- @@ -394,22 +430,25 @@ def __dlpack__( # here to tell users that the consumer's max_version is too # old to allow the data exchange to happen. - And this logic for the consumer in ``from_dlpack``: + And this logic for the consumer in :func:`~array_api.from_dlpack`: .. code:: python try: - x.__dlpack__(max_version=(1, 0)) + x.__dlpack__(max_version=(1, 0), ...) # if it succeeds, store info from the capsule named "dltensor_versioned", # and need to set the name to "used_dltensor_versioned" when we're done except TypeError: - x.__dlpack__() + x.__dlpack__(...) + + This logic is also applicable to handling of the new ``dl_device`` and ``copy`` + keywords. .. versionchanged:: 2022.12 Added BufferError. .. versionchanged:: 2023.12 - Added the ``max_version`` keyword. + Added the ``max_version``, ``dl_device``, and ``copy`` keywords. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -436,6 +475,8 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: METAL = 8 VPI = 9 ROCM = 10 + CUDA_MANAGED = 13 + ONE_API = 14 """ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index d0f967717..dec09db0c 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -214,7 +214,13 @@ def eye( """ -def from_dlpack(x: object, /) -> array: +def from_dlpack( + x: object, + /, + *, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: """ Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. @@ -222,11 +228,22 @@ def from_dlpack(x: object, /) -> array: ---------- x: object input (array) object. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``x`` supports DLPack, the output array must be on the same device as ``x``. Default: ``None``. + + The v2023.12 standard only mandates that a compliant library should offer a way for ``from_dlpack`` to return an array + whose underlying memory is accessible to the Python interpreter, when the corresponding ``device`` is provided. If the + array library does not support such cases at all, the function must raise ``BufferError``. If a copy must be made to + enable this support but ``copy`` is set to ``False``, the function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy, and raise ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse the existing memory buffer if possible and copy otherwise. Default: ``None``. Returns ------- out: array - an array containing the data in `x`. + an array containing the data in ``x``. .. admonition:: Note :class: note @@ -238,7 +255,7 @@ def from_dlpack(x: object, /) -> array: BufferError The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array may raise ``BufferError`` when the data cannot be exported as DLPack - (e.g., incompatible dtype or strides). It may also raise other errors + (e.g., incompatible dtype, strides, or device). It may also raise other errors when export fails for other reasons (e.g., not enough memory available to materialize the data). ``from_dlpack`` must propagate such exceptions. @@ -246,11 +263,34 @@ def from_dlpack(x: object, /) -> array: If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present on the input array. This may happen for libraries that are never able to export their data with DLPack. + ValueError + If data exchange is possible via an explicit copy but ``copy`` is set to ``False``. Notes ----- See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in order to handle DLPack versioning correctly. + + A way to move data from two array libraries to the same device (assumed supported by both libraries) in + a library-agnostic fashion is illustrated below: + + .. code:: python + + def func(x, y): + xp_x = x.__array_namespace__() + xp_y = y.__array_namespace__() + + # Other functions than `from_dlpack` only work if both arrays are from the same library. So if + # `y` is from a different one than `x`, let's convert `y` into an array of the same type as `x`: + if not xp_x == xp_y: + y = xp_x.from_dlpack(y, copy=True, device=x.device) + + # From now on use `xp_x.xxxxx` functions, as both arrays are from the library `xp_x` + ... + + + .. versionchanged:: 2023.12 + Added device and copy support. """ From cc11aa344d8dab03345acb563f37c25583af151a Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 14 Feb 2024 15:37:07 -0800 Subject: [PATCH 485/551] Add Array API inspection utilities (#689) --- spec/draft/API_specification/index.rst | 1 + spec/draft/API_specification/inspection.rst | 40 +++++ spec/draft/design_topics/device_support.rst | 29 ++-- src/_array_api_conf.py | 4 + src/array_api_stubs/_draft/__init__.py | 1 + src/array_api_stubs/_draft/_types.py | 59 +++++++ src/array_api_stubs/_draft/info.py | 170 ++++++++++++++++++++ 7 files changed, 290 insertions(+), 14 deletions(-) create mode 100644 spec/draft/API_specification/inspection.rst create mode 100644 src/array_api_stubs/_draft/info.py diff --git a/spec/draft/API_specification/index.rst b/spec/draft/API_specification/index.rst index 603131ab9..ffc3d3775 100644 --- a/spec/draft/API_specification/index.rst +++ b/spec/draft/API_specification/index.rst @@ -29,6 +29,7 @@ A conforming implementation of the array API standard must provide and support t function_and_method_signatures indexing indexing_functions + inspection linear_algebra_functions manipulation_functions searching_functions diff --git a/spec/draft/API_specification/inspection.rst b/spec/draft/API_specification/inspection.rst new file mode 100644 index 000000000..04691e712 --- /dev/null +++ b/spec/draft/API_specification/inspection.rst @@ -0,0 +1,40 @@ +Inspection +========== + + Array API specification for namespace inspection utilities. + +A conforming implementation of the array API standard must provide and support the following functions and associated inspection APIs. + + +Objects in API +-------------- + +.. currentmodule:: array_api.info + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + __array_namespace_info__ + + +Inspection APIs +--------------- + +In the namespace (or class) returned by ``__array_namespace_info__``, a conforming implementation of the array API standard must provide and support the following functions (or methods) for programmatically querying data type and device support, capabilities, and other specification-defined implementation-specific behavior, as documented in the functions described below. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + capabilities + default_device + default_dtypes + devices + dtypes diff --git a/spec/draft/design_topics/device_support.rst b/spec/draft/design_topics/device_support.rst index 29f0789bb..593b0b9fa 100644 --- a/spec/draft/design_topics/device_support.rst +++ b/spec/draft/design_topics/device_support.rst @@ -39,7 +39,7 @@ into library code which may have to do the following: Syntax for device assignment ---------------------------- -The array API will offer the following syntax for device assignment and +The array API provides the following syntax for device assignment and cross-device data transfer: 1. A ``.device`` property on the array object, which returns a ``Device`` object @@ -52,19 +52,20 @@ cross-device data transfer: 3. A ``.to_device`` method on the array object to copy an array to a different device. .. note:: - In the current API standard, the only way to obtain a ``Device`` object is from the - ``.device`` property on the array object. The standard does **not** include a universal - ``Device`` object recognized by all compliant libraries. Accordingly, the standard does - not provide a means of instantiating a ``Device`` object to point to a specific physical or - logical device. - - The choice to not include a standardized ``Device`` object may be revisited in a future revision of this standard. - - For array libraries which concern themselves with multi-device support, including CPU and GPU, - they are free to expose a library-specific device object (e.g., for creating an - array on a particular device). While a library-specific device object can be used as input to - ``to_device``, beware that this will mean non-portability as code will be specific to - that library. + The current API standard does **not** include a universal ``Device`` object + recognized by all compliant libraries. Accordingly, the standard does not + provide a means of instantiating a ``Device`` object to point to a specific + physical or logical device. + + The choice to not include a standardized ``Device`` object may be revisited + in a future revision of this standard. + + For array libraries which concern themselves with multi-device support, + including CPU and GPU, they are free to expose a library-specific device + object (e.g., for creating an array on a particular device). While a + library-specific device object can be used as input to ``to_device``, beware + that this will mean non-portability as code will be specific to that + library. Semantics --------- diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 9c5722f94..9233df3c4 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -72,6 +72,10 @@ ("py:class", ".*PyCapsule"), ("py:class", ".*finfo_object"), ("py:class", ".*iinfo_object"), + ("py:class", ".*Info"), + ("py:class", ".*Capabilities"), + ("py:class", ".*DefaultDataTypes"), + ("py:class", ".*DataTypes"), ] # In array_object.py we have to use aliased names for some types because they # would otherwise refer back to method objects of array diff --git a/src/array_api_stubs/_draft/__init__.py b/src/array_api_stubs/_draft/__init__.py index 12b6d9fbb..8415f2765 100644 --- a/src/array_api_stubs/_draft/__init__.py +++ b/src/array_api_stubs/_draft/__init__.py @@ -16,6 +16,7 @@ from .utility_functions import * from . import linalg from . import fft +from . import info __array_api_version__: str = "YYYY.MM" diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 2a73dda24..7c3d903d7 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -25,6 +25,10 @@ "finfo_object", "iinfo_object", "Enum", + "DefaultDataTypes", + "DataTypes", + "Capabilities", + "Info", ] from dataclasses import dataclass @@ -35,6 +39,7 @@ Optional, Sequence, Tuple, + TypedDict, TypeVar, Union, Protocol, @@ -83,3 +88,57 @@ def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: def __len__(self, /) -> int: ... + + +class Info(Protocol): + """Namespace returned by `__array_namespace_info__`.""" + + def capabilities(self) -> Capabilities: + ... + + def default_device(self) -> device: + ... + + def default_dtypes(self, *, device: Optional[device]) -> DefaultDataTypes: + ... + + def devices(self) -> List[device]: + ... + + def dtypes( + self, *, device: Optional[device], kind: Optional[Union[str, Tuple[str, ...]]] + ) -> DataTypes: + ... + + +DefaultDataTypes = TypedDict( + "DefaultDataTypes", + { + "real floating": dtype, + "complex floating": dtype, + "integral": dtype, + "indexing": dtype, + }, +) +DataTypes = TypedDict( + "DataTypes", + { + "bool": dtype, + "float32": dtype, + "float64": dtype, + "complex64": dtype, + "complex128": dtype, + "int8": dtype, + "int16": dtype, + "int32": dtype, + "int64": dtype, + "uint8": dtype, + "uint16": dtype, + "uint32": dtype, + "uint64": dtype, + }, + total=False, +) +Capabilities = TypedDict( + "Capabilities", {"boolean indexing": bool, "data-dependent shapes": bool} +) diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py new file mode 100644 index 000000000..f70418405 --- /dev/null +++ b/src/array_api_stubs/_draft/info.py @@ -0,0 +1,170 @@ +__all__ = [ + "__array_namespace_info__", + "capabilities", + "default_device", + "default_dtypes", + "devices", + "dtypes", +] + +from ._types import ( + Optional, + Union, + Tuple, + List, + device, + dtype, + DefaultDataTypes, + DataTypes, + Capabilities, + Info, +) + + +def __array_namespace_info__() -> Info: + """ + Returns a namespace with Array API namespace inspection utilities. + + Returns + ------- + out: Info + An object containing Array API namespace inspection utilities. + + Notes + ----- + + The returned object may be either a namespace or a class, so long as an Array API user can access inspection utilities as follows: + + :: + + info = xp.__array_namespace_info__() + info.capabilities() + info.devices() + info.dtypes() + info.default_dtypes() + # ... + """ + + +def capabilities() -> Capabilities: + """ + Returns a dictionary of array library capabilities. + + The dictionary must contain the following keys: + + - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + + Returns + ------- + out: Capabilities + a dictionary of array library capabilities. + """ + + +def default_device() -> device: + """ + Returns the default device. + + Returns + ------- + out: device + an object corresponding to the default device. + """ + + +def default_dtypes( + *, + device: Optional[device] = None, +) -> DefaultDataTypes: + """ + Returns a dictionary containing default data types. + + The dictionary must have the following keys: + + - `"real floating"`: default real floating-point data type. + - `"complex floating"`: default complex floating-point data type. + - `"integral"`: default integral data type. + - `"indexing"`: default array index data type. + + Dictionary values must be the corresponding data type object. + + Parameters + ---------- + device: Optional[device] + device for which to return default data types. If ``device`` is ``None``, the returned data types must be the default data types for the current device; otherwise, the returned data types must be default data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the default data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the default data types for the default device. + + Returns + ------- + out: DefaultDataTypes + a dictionary containing the default data type for respective data type kinds. + """ + + +def dtypes( + *, + device: Optional[device] = None, + kind: Optional[Union[str, Tuple[str, ...]]] = None, +) -> DataTypes: + """ + Returns a dictionary of supported *Array API* data types. + + .. note:: + While specification-conforming array libraries may support additional data types which are not present in this specification, data types which are not present in this specification should not be included in the returned dictionary. + + .. note:: + Specification-conforming array libraries must only return supported data types having expected properties as described in :ref:`data-types`. For example, if a library decides to alias ``float32`` as ``float64``, that library must not include ``float64`` in the dictionary of supported data types. + + Parameters + ---------- + kind: Optional[Union[str, Tuple[str, ...]]] + data type kind. + + - If ``kind`` is ``None``, the function must return a dictionary containing all supported Array API data types. + + - If ``kind`` is a string, the function must return a dictionary containing the data types belonging to the specified data type kind. The following data type kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of data type kinds, and the function must return a dictionary containing the data types belonging to at least one of the specified data type kinds. + + Default: ``None``. + device: Optional[device] + device for which to return supported data types. If ``device`` is ``None``, the returned data types must be the supported data types for the current device; otherwise, the returned data types must be supported data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the supported data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the supported data types for the default device. + + Returns + ------- + out: DataTypes + a dictionary containing supported data types. + + .. note:: + Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + """ + + +def devices() -> List[device]: + """ + Returns a list of supported devices which are available at runtime. + + Returns + ------- + out: List[device] + a list of supported devices. + + Notes + ----- + + Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + """ From ba787e3aaa75d41bcafa59ddc0915f61b483a403 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Fri, 16 Feb 2024 17:32:18 +0100 Subject: [PATCH 486/551] Add recommendation on what to do with DLPack read-only flag (#749) This is a follow-up to the discussion in gh-191. It's a recommendation rather than a hard requirement to allow implementers some choice. That said, this is how things worked in practice before DLPack 1.0 as well, since there was no flag to represent read-only. Experience with JAX showed that exposing shared memory was preferred by users over raising or always making a copy of the data on the producer side. --- src/array_api_stubs/_draft/array_object.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 5017bf87c..2a33a60ae 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -444,6 +444,12 @@ def __dlpack__( This logic is also applicable to handling of the new ``dl_device`` and ``copy`` keywords. + DLPack 1.0 added a flag to indicate that the array is read-only + (``DLPACK_FLAG_BITMASK_READ_ONLY``). A consumer that does not support + read-only arrays should ignore this flag (this is preferred over + raising an exception; the user is then responsible for ensuring the + memory isn't modified). + .. versionchanged:: 2022.12 Added BufferError. From bc48a1a3f73a64fdc6677f361bff11ee2baf7f97 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 21 Feb 2024 12:18:13 -0800 Subject: [PATCH 487/551] Add `hypot` specification for computing the square root of the sum of squares (#703) --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index f0b69cfcb..4919cff98 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -46,6 +46,7 @@ Objects in API floor_divide greater greater_equal + hypot imag isfinite isinf diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index c71b6674b..ee6ea27f3 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -28,6 +28,7 @@ "floor_divide", "greater", "greater_equal", + "hypot", "imag", "isfinite", "isinf", @@ -1367,6 +1368,51 @@ def greater_equal(x1: array, x2: array, /) -> array: """ +def hypot(x1: array, x2: array, /) -> array: + r""" + Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + The value computed by this function may be interpreted as the length of the hypotenuse of a right-angled triangle with sides of length ``x1_i`` and ``x2_i``, the distance of a point ``(x1_i, x2_i)`` from the origin ``(0, 0)``, or the magnitude of a complex number ``x1_i + x2_i * 1j``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``+infinity`` or ``-infinity`` and ``x2_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x2_i`` is ``+infinity`` or ``-infinity`` and ``x1_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x2_i)``. + - If ``x2_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x1_i)``. + - If ``x1_i`` is a finite number or ``NaN`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is a finite number or ``NaN`` and ``x1_i`` is ``NaN``, the result is ``NaN``. + - Underflow may only occur when both arguments are subnormal and the correct result is also subnormal. + + For real-valued floating-point operands, ``hypot(x1, x2)`` must equal ``hypot(x2, x1)``, ``hypot(x1, -x2)``, ``hypot(-x1, x2)``, and ``hypot(-x1, -x2)``. + + .. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, conforming implementations may vary in their support for subnormal numbers. + """ + + def imag(x: array, /) -> array: """ Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. From 6e9c48720fcde6941d48596e134c869c011a6a65 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 21 Feb 2024 23:18:27 -0800 Subject: [PATCH 488/551] docs: add note concerning signed zeros (#751) --- .../_draft/elementwise_functions.py | 14 ++++++----- .../_draft/statistical_functions.py | 24 +++++++++---------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index ee6ea27f3..4dc0c949f 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -1905,9 +1905,6 @@ def maximum(x1: array, x2: array, /) -> array: r""" Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x1: array @@ -1923,6 +1920,10 @@ def maximum(x1: array, x2: array, /) -> array: Notes ----- + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, @@ -1935,9 +1936,6 @@ def minimum(x1: array, x2: array, /) -> array: r""" Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x1: array @@ -1953,6 +1951,10 @@ def minimum(x1: array, x2: array, /) -> array: Notes ----- + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 496440535..2304ece80 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -64,12 +64,6 @@ def max( """ Calculates the maximum value of the input array ``x``. - .. note:: - When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). - - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x: array @@ -87,6 +81,12 @@ def max( Notes ----- + When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, @@ -144,12 +144,6 @@ def min( """ Calculates the minimum value of the input array ``x``. - .. note:: - When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). - - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- x: array @@ -167,6 +161,12 @@ def min( Notes ----- + When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + **Special Cases** For floating-point operands, From 11273e62fbfbc17b2a2f61535520ea3e34d71d52 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 22 Feb 2024 12:40:28 -0800 Subject: [PATCH 489/551] docs: clarify shape of `values` and order of `counts` (#752) --- src/array_api_stubs/_draft/set_functions.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 394fa2b17..25a897355 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -34,10 +34,10 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: out: Tuple[array, array, array, array] a namedtuple ``(values, indices, inverse_indices, counts)`` whose - - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. - - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of a flattened ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. - third element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and must have the default array index data type. - - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The returned array must have same shape as ``values`` and must have the default array index data type. + - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. .. note:: The order of unique elements is not specified and may vary between implementations. @@ -78,8 +78,8 @@ def unique_counts(x: array, /) -> Tuple[array, array]: out: Tuple[array, array] a namedtuple `(values, counts)` whose - - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. - - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The returned array must have same shape as ``values`` and must have the default array index data type. + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. .. note:: The order of unique elements is not specified and may vary between implementations. @@ -120,7 +120,7 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: out: Tuple[array, array] a namedtuple ``(values, inverse_indices)`` whose - - first element must have the field name ``values`` and must be an array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. - second element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and have the default array index data type. .. note:: @@ -158,7 +158,7 @@ def unique_values(x: array, /) -> array: Returns ------- out: array - an array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. + a one-dimensional array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. .. note:: The order of unique elements is not specified and may vary between implementations. From 9d200ea3478a27bc3e93e3543a73369cfdc60ec0 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 22 Feb 2024 12:40:58 -0800 Subject: [PATCH 490/551] Add `repeat` to the specification (#690) --- .../manipulation_functions.rst | 1 + .../_draft/manipulation_functions.py | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/spec/draft/API_specification/manipulation_functions.rst b/spec/draft/API_specification/manipulation_functions.rst index 680efb55f..395c1c3e2 100644 --- a/spec/draft/API_specification/manipulation_functions.rst +++ b/spec/draft/API_specification/manipulation_functions.rst @@ -25,6 +25,7 @@ Objects in API flip moveaxis permute_dims + repeat reshape roll squeeze diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 74538a8a3..4d7a17dda 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -6,6 +6,7 @@ "flip", "moveaxis", "permute_dims", + "repeat", "reshape", "roll", "squeeze", @@ -159,6 +160,53 @@ def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: """ +def repeat( + x: array, + repeats: Union[int, array], + /, + *, + axis: Optional[int] = None, +) -> array: + """ + Repeats each element of an array a specified number of times on a per-element basis. + + .. admonition:: Data-dependent output shape + :class: important + + When ``repeats`` is an array, the shape of the output array for this function depends on the data values in the ``repeats`` array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing the values in ``repeats``. Accordingly, such libraries may choose to omit support for ``repeats`` arrays; however, conforming implementations must support providing a literal ``int``. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array containing elements to repeat. + repeats: Union[int, array] + the number of repetitions for each element. + + If ``axis`` is ``None``, let ``N = prod(x.shape)`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(N,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(N,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape `(N,)`. + + If ``axis`` is not ``None``, let ``M = x.shape[axis]`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(M,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(M,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape ``(M,)``. + + If ``repeats`` is an array, the array must have an integer data type. + + .. note:: + For specification-conforming array libraries supporting hardware acceleration, providing an array for ``repeats`` may cause device synchronization due to an unknown output shape. For those array libraries where synchronization concerns are applicable, conforming array libraries are advised to include a warning in their documentation regarding potential performance degradation when ``repeats`` is an array. + + axis: Optional[int] + the axis (dimension) along which to repeat elements. If ``axis`` is `None`, the function must flatten the input array ``x`` and then repeat elements of the flattened input array and return the result as a one-dimensional output array. A flattened input array must be flattened in row-major, C-style order. Default: ``None``. + + Returns + ------- + out: array + an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + """ + + def reshape( x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None ) -> array: From cb44271dda95468e596fe7dcd0c08462bc7e0d60 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 25 Feb 2024 23:54:19 -0800 Subject: [PATCH 491/551] docs: add changelog for v2023.12 specification revision PR-URL: https://github.com/data-apis/array-api/pull/754 Reviewed-by: Athan Reines --- CHANGELOG.md | 132 ++++++++++++++++++ .../_2022_12/indexing_functions.py | 2 +- src/array_api_stubs/_draft/array_object.py | 25 +++- .../_draft/creation_functions.py | 3 + .../_draft/data_type_functions.py | 3 + .../_draft/elementwise_functions.py | 12 ++ src/array_api_stubs/_draft/fft.py | 27 ++++ .../_draft/indexing_functions.py | 5 +- src/array_api_stubs/_draft/info.py | 27 ++++ src/array_api_stubs/_draft/linalg.py | 12 +- .../_draft/linear_algebra_functions.py | 12 +- .../_draft/manipulation_functions.py | 20 +++ .../_draft/searching_functions.py | 2 + src/array_api_stubs/_draft/set_functions.py | 12 ++ .../_draft/statistical_functions.py | 14 ++ 15 files changed, 298 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0897e4ea5..eace3f0a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,138 @@ This changelog is organized by specification version and notes all changes with respect to the previous version. Within the section for a specific version (e.g., v2022.12), separate sections are used for (a) changes to existing APIs and requirements, (b) new APIs and new requirements, and (c) errata. +## v2023.12 + +### Updates + +> Updates to existing APIs and requirements. + +#### Normative + +- Clarify expectations concerning exception handling ([gh-613](https://github.com/data-apis/array-api/pull/613)) +- Clarify that the constant `newaxis` is an alias of `None` ([gh-687](https://github.com/data-apis/array-api/pull/687)) +- Add design discussion on lazy versus eager implementations ([gh-708](https://github.com/data-apis/array-api/pull/708)) +- Revise guidance to require a minimum upper bound for supported ranks ([gh-702](https://github.com/data-apis/array-api/pull/702)) +- Relax design requirements for positional and keyword-only arguments ([gh-730](https://github.com/data-apis/array-api/pull/730)) +- Add recommendation to `__dlpack__` for handling read-only arrays ([gh-749](https://github.com/data-apis/array-api/pull/749)) + +#### APIs + +- `__bool__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__complex__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__dlpack__`: add `max_version` keyword argument to support versioning ([gh-602](https://github.com/data-apis/array-api/pull/602)) +- `__dlpack__`: add `dl_device` and `copy` keyword arguments ([gh-741](https://github.com/data-apis/array-api/pull/741)) +- `__float__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__index__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `__int__`: allow lazy implementations to raise from intrinsically eager functions ([gh-652](https://github.com/data-apis/array-api/pull/652)) +- `astype`: add support for an optional `device` keyword argument ([gh-665](https://github.com/data-apis/array-api/pull/665)) +- `from_dlpack`: require exceptions to address unsupported use cases ([gh-709](https://github.com/data-apis/array-api/pull/709)) +- `from_dlpack`: add support for `copy` and `device` keywords ([gh-741](https://github.com/data-apis/array-api/pull/741)) +- `max`: clarify that the order of signed zeros is unspecified ([gh-751](https://github.com/data-apis/array-api/pull/751)) +- `min`: clarify that the order of signed zeros is unspecified ([gh-751](https://github.com/data-apis/array-api/pull/751)) +- `take`: explicitly leave out-of-bounds behavior unspecified ([gh-701](https://github.com/data-apis/array-api/pull/701)) +- `tensordot`: allow negative axes ([gh-625](https://github.com/data-apis/array-api/pull/625)) +- `to_device`: clarify behavior when a provided `device` object corresponds to the same device on which an array instance resides ([gh-742](https://github.com/data-apis/array-api/pull/742)) +- `unique_all`: clarify the shape of the array containing unique values and the order of returned counts ([gh-752](https://github.com/data-apis/array-api/pull/752)) +- `unique_counts`: clarify the shape of the array containing unique values and the order of returned counts ([gh-752](https://github.com/data-apis/array-api/pull/752)) +- `unique_inverse`: clarify the shape of the array containing unique values ([gh-752](https://github.com/data-apis/array-api/pull/752)) +- `unique_values`: clarify the shape of the returned array ([gh-752](https://github.com/data-apis/array-api/pull/752)) + +#### Extensions + +> Updates to APIs and requirements included as part of specification extensions. + +- `fft.*`: clarify behavior of the `n` and `s` keyword arguments and the expected output array shape ([gh-720](https://github.com/data-apis/array-api/pull/720) and [gh-746](https://github.com/data-apis/array-api/pull/746); backported to v2022.12 revision of Array API specification) + +* * * + +### Additions + +> New APIs and requirements added to the specification. + +#### APIs + +The following APIs were added to the specification: + +- `__array_namespace_info__`: namespace with Array API namespace inspection utilities ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `clip`: clamp each element of an input array to a specified range ([gh-715](https://github.com/data-apis/array-api/pull/715)) +- `copysign`: compose a floating-point value with the magnitude of a `x1_i` and the sign of `x2_i` ([gh-693](https://github.com/data-apis/array-api/pull/693)) +- `cumulative_sum`: calculate the cumulative sum ([gh-653](https://github.com/data-apis/array-api/pull/653)) +- `hypot`: compute the square root of the sum of squares for each element in an array ([gh-703](https://github.com/data-apis/array-api/pull/703)) +- `maximum`: compute the maximum value for each element of an array relative to the respective element in another array ([gh-713](https://github.com/data-apis/array-api/pull/713)) +- `minimum`: compute the minimum value for each element of an array relative to the respective element in another array ([gh-713](https://github.com/data-apis/array-api/pull/713)) +- `moveaxis`: move array axes to new positions, while leaving other axes in their original positions ([gh-656](https://github.com/data-apis/array-api/pull/656)) +- `repeat`: repeat each element of an array a specified number of times ([gh-690](https://github.com/data-apis/array-api/pull/690)) +- `searchsorted`: find the indices into `x1` such that, if the corresponding elements in `x2` were inserted before the indices, the order of `x1`, when sorted in ascending order, would be preserved ([gh-699](https://github.com/data-apis/array-api/pull/699)) +- `signbit`: determine whether the sign bit is set for each element of an array ([gh-705](https://github.com/data-apis/array-api/pull/705)) +- `tile`: construct an array by tiling an input array ([gh-692](https://github.com/data-apis/array-api/pull/692)) +- `unstack`: split an array into a sequence of arrays along a given axis ([gh-604](https://github.com/data-apis/array-api/pull/604)) + +#### Inspection APIs + +The following inspection APIs were added to the specification: + +- `capabilities`: return a dictionary of array library capabilities ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `default_device`: return the default device ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `default_dtypes`: return a dictionary containing default data types ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `dtypes`: return a dictionary support Array API data types ([gh-689](https://github.com/data-apis/array-api/pull/689)) +- `devices`: return a list of supported devices ([gh-689](https://github.com/data-apis/array-api/pull/689)) + +* * * + +### Breaking Changes + +The following is a list of breaking changes relative to the previous version of the specification: + +- `prod`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) +- `sum`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) +- `vecdot`: only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) + +#### Extensions + +The following is a list of breaking changes in specification extensions relative to the previous version of the specification: + +- `fft.fft`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.fftn`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.hfft`: require the input array to have a complex-valued floating-point data type and require that the output array have a real-valued data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.ifft`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.ifftn`: require the input array to have a complex-valued floating-point data type and require that the output array have the same data type as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.irfft`: require the output array have a real-valued floating-point data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.irfftn`: require the output array have a real-valued floating-point data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.fftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `fft.rfftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) +- `linalg.cross`: broadcast only along non-compute axes and only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) +- `linalg.trace`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) + +* * * + +### Errata + +The following is a list of fixes and points of clarification with regard to the previous version of the specification: + +- `__getitem__`: clarify typing to allow `None` in indexing ([gh-674](https://github.com/data-apis/array-api/pull/674) and [gh-687](https://github.com/data-apis/array-api/pull/687)) +- `__ge__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `__gt__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `__le__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `__lt__`: clarify that the operation is only defined for arrays having real-valued data types ([gh-736](https://github.com/data-apis/array-api/pull/736)) +- `abs`: fix typo in return value description ([gh-633](https://github.com/data-apis/array-api/pull/633)) +- `asarray`: fix typo in `device` keyword argument description ([gh-681](https://github.com/data-apis/array-api/pull/681)) +- `conj`: fix typo in parameter description ([gh-706](https://github.com/data-apis/array-api/pull/706)) +- `finfo_object`: fix missing `dtype` attribute ([gh-639](https://github.com/data-apis/array-api/pull/639)) +- `fft.*`: fix various typing issues ([gh-720](https://github.com/data-apis/array-api/pull/720)) +- `iinfo_object`: fix missing `dtype` attribute ([gh-639](https://github.com/data-apis/array-api/pull/639)) +- `linalg.qr`: fix typo in function description ([gh-661](https://github.com/data-apis/array-api/pull/661)) +- `linalg.cholesky`: fix typo in function description ([gh-677](https://github.com/data-apis/array-api/pull/677)) +- `linalg.svd`: fix return type ([gh-619](https://github.com/data-apis/array-api/pull/619)) +- `prod`: clarify type promotion behavior when `dtype=None` ([gh-666](https://github.com/data-apis/array-api/pull/666)) +- `sum`: clarify type promotion behavior when `dtype=None` ([gh-666](https://github.com/data-apis/array-api/pull/666)) +- `take`: fix typing for optional `axis` keyword argument ([gh-644](https://github.com/data-apis/array-api/pull/644)) +- `tensordot`: fix typo in parameter description ([gh-622](https://github.com/data-apis/array-api/pull/622)) +- `trace`: clarify type promotion behavior when `dtype=None` ([gh-666](https://github.com/data-apis/array-api/pull/666)) +- `vecdot`: fix definition of complex inner product ([gh-723](https://github.com/data-apis/array-api/pull/723)) + +* * * + ## v2022.12 ### Updates diff --git a/src/array_api_stubs/_2022_12/indexing_functions.py b/src/array_api_stubs/_2022_12/indexing_functions.py index 0cbad55ab..5dd74461d 100644 --- a/src/array_api_stubs/_2022_12/indexing_functions.py +++ b/src/array_api_stubs/_2022_12/indexing_functions.py @@ -14,7 +14,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: input array. indices: array array indices. The array must be one-dimensional and have an integer data type. - axis: int + axis: Optional[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. diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 2a33a60ae..6dd70c278 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -247,6 +247,9 @@ def __bool__(self: array, /) -> bool: .. versionchanged:: 2022.12 Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __complex__(self: array, /) -> complex: @@ -285,6 +288,9 @@ def __complex__(self: array, /) -> complex: The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __dlpack__( @@ -451,10 +457,13 @@ def __dlpack__( memory isn't modified). .. versionchanged:: 2022.12 - Added BufferError. + Added BufferError. .. versionchanged:: 2023.12 - Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + + .. versionchanged:: 2023.12 + Added recommendation for handling read-only arrays. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -539,6 +548,9 @@ def __float__(self: array, /) -> float: .. versionchanged:: 2022.12 Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __floordiv__(self: array, other: Union[int, float, array], /) -> array: @@ -664,6 +676,9 @@ def __index__(self: array, /) -> int: **Lazy implementations** The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __int__(self: array, /) -> int: @@ -711,6 +726,9 @@ def __int__(self: array, /) -> int: .. versionchanged:: 2022.12 Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. """ def __invert__(self: array, /) -> array: @@ -1192,6 +1210,9 @@ def to_device( - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. + + .. versionchanged:: 2023.12 + Clarified behavior when a provided ``device`` object corresponds to the device on which an array instance resides. """ diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index dec09db0c..6de79268e 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -289,6 +289,9 @@ def func(x, y): ... + .. versionchanged:: 2023.12 + Required exceptions to address unsupported use cases. + .. versionchanged:: 2023.12 Added device and copy support. """ diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index 81d518807..e12d349c6 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -57,6 +57,9 @@ def astype( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Added device keyword argument support. """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 4dc0c949f..4462329d6 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -806,6 +806,8 @@ def clip( - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + + .. versionadded:: 2023.12 """ @@ -880,6 +882,8 @@ def copysign(x1: array, x2: array, /) -> array: - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + + .. versionadded:: 2023.12 """ @@ -1410,6 +1414,8 @@ def hypot(x1: array, x2: array, /) -> array: IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, conforming implementations may vary in their support for subnormal numbers. + + .. versionadded:: 2023.12 """ @@ -1929,6 +1935,8 @@ def maximum(x1: array, x2: array, /) -> array: For floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 """ @@ -1960,6 +1968,8 @@ def minimum(x1: array, x2: array, /) -> array: For floating-point operands, - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 """ @@ -2390,6 +2400,8 @@ def signbit(x: array, /) -> array: - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index bdd7a9c83..4e8131c8b 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -64,6 +64,9 @@ def fft( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -113,6 +116,9 @@ def ifft( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -168,6 +174,9 @@ def fftn( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -223,6 +232,9 @@ def ifftn( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. """ @@ -323,6 +335,9 @@ def irfft( - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. """ @@ -435,6 +450,9 @@ def irfftn( - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. """ @@ -481,6 +499,9 @@ def hfft( ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. """ @@ -559,6 +580,9 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. """ @@ -593,6 +617,9 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. """ diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index f3bf0fc14..35066a4a2 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -20,7 +20,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. note:: This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - axis: int + axis: Optional[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. @@ -34,4 +34,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: ----- .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Out-of-bounds behavior is explicitly left unspecified. """ diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index f70418405..b755ca2c0 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -43,6 +43,8 @@ def __array_namespace_info__() -> Info: info.dtypes() info.default_dtypes() # ... + + .. versionadded: 2023.12 """ @@ -59,6 +61,11 @@ def capabilities() -> Capabilities: ------- out: Capabilities a dictionary of array library capabilities. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -70,6 +77,11 @@ def default_device() -> device: ------- out: device an object corresponding to the default device. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -101,6 +113,11 @@ def default_dtypes( ------- out: DefaultDataTypes a dictionary containing the default data type for respective data type kinds. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -151,6 +168,11 @@ def dtypes( .. note:: Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + + Notes + ----- + + .. versionadded: 2023.12 """ @@ -167,4 +189,9 @@ def devices() -> List[device]: ----- Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + + Notes + ----- + + .. versionadded: 2023.12 """ diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 903f928d8..0950e6937 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -102,15 +102,18 @@ def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: Notes ----- + **Raises** + + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + .. versionchanged:: 2022.12 Added support for broadcasting. .. versionchanged:: 2022.12 Added complex data type support. - **Raises** - - - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + .. versionchanged:: 2023.12 + Restricted broadcasting to only non-compute axes and required that ``axis`` be a negative integer. """ @@ -772,6 +775,9 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. """ diff --git a/src/array_api_stubs/_draft/linear_algebra_functions.py b/src/array_api_stubs/_draft/linear_algebra_functions.py index eea898a6b..da4c97743 100644 --- a/src/array_api_stubs/_draft/linear_algebra_functions.py +++ b/src/array_api_stubs/_draft/linear_algebra_functions.py @@ -116,6 +116,9 @@ def tensordot( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Allow negative axes. """ @@ -151,10 +154,13 @@ def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: Notes ----- - .. versionchanged:: 2022.12 - Added complex data type support. - **Raises** - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted ``axis`` to only negative integers. """ diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 4d7a17dda..87f9511b0 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -139,6 +139,11 @@ def moveaxis( ------- out: array an array containing reordered axes. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2023.12 """ @@ -204,6 +209,11 @@ def repeat( ------- out: array an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + + Notes + ----- + + .. versionadded:: 2023.12 """ @@ -327,6 +337,11 @@ def tile(x: array, repetitions: Tuple[int, ...], /): ------- out: array a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + + Notes + ----- + + .. versionadded:: 2023.12 """ @@ -345,4 +360,9 @@ def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: ------- out: Tuple[array, ...] tuple of slices along the given dimension. All the arrays have the same shape. + + Notes + ----- + + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index dda000e74..029459b9a 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -134,6 +134,8 @@ def searchsorted( For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/set_functions.py b/src/array_api_stubs/_draft/set_functions.py index 25a897355..5b7e9a56c 100644 --- a/src/array_api_stubs/_draft/set_functions.py +++ b/src/array_api_stubs/_draft/set_functions.py @@ -47,6 +47,9 @@ def unique_all(x: array, /) -> Tuple[array, array, array, array]: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. """ @@ -89,6 +92,9 @@ def unique_counts(x: array, /) -> Tuple[array, array]: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. """ @@ -131,6 +137,9 @@ def unique_inverse(x: array, /) -> Tuple[array, array]: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior. """ @@ -168,4 +177,7 @@ def unique_values(x: array, /) -> array: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required that the output array must be one-dimensional. """ diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 2304ece80..9d3563e26 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -51,6 +51,8 @@ def cumulative_sum( **Special Cases** For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionadded:: 2023.12 """ @@ -92,6 +94,9 @@ def max( For floating-point operands, - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. """ @@ -172,6 +177,9 @@ def min( For floating-point operands, - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. """ @@ -222,6 +230,9 @@ def prod( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. """ @@ -314,6 +325,9 @@ def sum( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. """ From fbc9ddec2f0366df069901a1d99580b5791f8772 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:04:18 -0800 Subject: [PATCH 492/551] build: create new release --- .DS_Store | Bin 0 -> 6148 bytes LICENSE | 2 +- Makefile | 3 +- .../API_specification/array_object.rst | 308 ++ .../API_specification/broadcasting.rst | 128 + spec/2023.12/API_specification/constants.rst | 26 + .../API_specification/creation_functions.rst | 36 + .../API_specification/data_type_functions.rst | 26 + spec/2023.12/API_specification/data_types.rst | 143 + .../elementwise_functions.rst | 84 + .../function_and_method_signatures.rst | 63 + spec/2023.12/API_specification/index.rst | 41 + spec/2023.12/API_specification/indexing.rst | 208 ++ .../API_specification/indexing_functions.rst | 23 + spec/2023.12/API_specification/inspection.rst | 40 + .../linear_algebra_functions.rst | 23 + .../manipulation_functions.rst | 34 + .../API_specification/searching_functions.rst | 27 + .../API_specification/set_functions.rst | 24 + .../API_specification/sorting_functions.rst | 31 + .../statistical_functions.rst | 28 + .../API_specification/type_promotion.rst | 148 + .../API_specification/utility_functions.rst | 22 + spec/2023.12/API_specification/version.rst | 22 + spec/2023.12/assumptions.md | 77 + spec/2023.12/benchmark_suite.md | 3 + spec/2023.12/changelog.rst | 5 + spec/2023.12/conf.py | 13 + spec/2023.12/design_topics/C_API.rst | 94 + spec/2023.12/design_topics/accuracy.rst | 77 + .../2023.12/design_topics/complex_numbers.rst | 61 + .../copies_views_and_mutation.rst | 77 + .../data_dependent_output_shapes.rst | 15 + .../design_topics/data_interchange.rst | 105 + spec/2023.12/design_topics/device_support.rst | 112 + spec/2023.12/design_topics/exceptions.rst | 28 + spec/2023.12/design_topics/index.rst | 18 + spec/2023.12/design_topics/lazy_eager.rst | 43 + spec/2023.12/design_topics/parallelism.rst | 24 + spec/2023.12/design_topics/static_typing.rst | 50 + .../fourier_transform_functions.rst | 45 + spec/2023.12/extensions/index.rst | 34 + .../extensions/linear_algebra_functions.rst | 116 + spec/2023.12/future_API_evolution.md | 60 + spec/2023.12/index.rst | 37 + spec/2023.12/license.rst | 9 + spec/2023.12/purpose_and_scope.md | 470 +++ spec/2023.12/usage_data.md | 86 + spec/2023.12/use_cases.md | 235 ++ spec/2023.12/verification_test_suite.md | 62 + spec/_ghpages/versions.json | 1 + src/.DS_Store | Bin 0 -> 6148 bytes src/_array_api_conf.py | 2 +- src/array_api_stubs/_2023_12/__init__.py | 25 + src/array_api_stubs/_2023_12/_types.py | 144 + src/array_api_stubs/_2023_12/array_object.py | 1219 ++++++++ src/array_api_stubs/_2023_12/constants.py | 30 + .../_2023_12/creation_functions.py | 647 ++++ .../_2023_12/data_type_functions.py | 228 ++ src/array_api_stubs/_2023_12/data_types.py | 22 + .../_2023_12/elementwise_functions.py | 2774 +++++++++++++++++ src/array_api_stubs/_2023_12/fft.py | 683 ++++ .../_2023_12/indexing_functions.py | 40 + src/array_api_stubs/_2023_12/info.py | 197 ++ src/array_api_stubs/_2023_12/linalg.py | 850 +++++ .../_2023_12/linear_algebra_functions.py | 166 + .../_2023_12/manipulation_functions.py | 368 +++ .../_2023_12/searching_functions.py | 159 + src/array_api_stubs/_2023_12/set_functions.py | 183 ++ .../_2023_12/sorting_functions.py | 58 + .../_2023_12/statistical_functions.py | 374 +++ .../_2023_12/utility_functions.py | 86 + src/array_api_stubs/__init__.py | 2 +- 73 files changed, 11700 insertions(+), 4 deletions(-) create mode 100644 .DS_Store create mode 100644 spec/2023.12/API_specification/array_object.rst create mode 100644 spec/2023.12/API_specification/broadcasting.rst create mode 100644 spec/2023.12/API_specification/constants.rst create mode 100644 spec/2023.12/API_specification/creation_functions.rst create mode 100644 spec/2023.12/API_specification/data_type_functions.rst create mode 100644 spec/2023.12/API_specification/data_types.rst create mode 100644 spec/2023.12/API_specification/elementwise_functions.rst create mode 100644 spec/2023.12/API_specification/function_and_method_signatures.rst create mode 100644 spec/2023.12/API_specification/index.rst create mode 100644 spec/2023.12/API_specification/indexing.rst create mode 100644 spec/2023.12/API_specification/indexing_functions.rst create mode 100644 spec/2023.12/API_specification/inspection.rst create mode 100644 spec/2023.12/API_specification/linear_algebra_functions.rst create mode 100644 spec/2023.12/API_specification/manipulation_functions.rst create mode 100644 spec/2023.12/API_specification/searching_functions.rst create mode 100644 spec/2023.12/API_specification/set_functions.rst create mode 100644 spec/2023.12/API_specification/sorting_functions.rst create mode 100644 spec/2023.12/API_specification/statistical_functions.rst create mode 100644 spec/2023.12/API_specification/type_promotion.rst create mode 100644 spec/2023.12/API_specification/utility_functions.rst create mode 100644 spec/2023.12/API_specification/version.rst create mode 100644 spec/2023.12/assumptions.md create mode 100644 spec/2023.12/benchmark_suite.md create mode 100644 spec/2023.12/changelog.rst create mode 100644 spec/2023.12/conf.py create mode 100644 spec/2023.12/design_topics/C_API.rst create mode 100644 spec/2023.12/design_topics/accuracy.rst create mode 100644 spec/2023.12/design_topics/complex_numbers.rst create mode 100644 spec/2023.12/design_topics/copies_views_and_mutation.rst create mode 100644 spec/2023.12/design_topics/data_dependent_output_shapes.rst create mode 100644 spec/2023.12/design_topics/data_interchange.rst create mode 100644 spec/2023.12/design_topics/device_support.rst create mode 100644 spec/2023.12/design_topics/exceptions.rst create mode 100644 spec/2023.12/design_topics/index.rst create mode 100644 spec/2023.12/design_topics/lazy_eager.rst create mode 100644 spec/2023.12/design_topics/parallelism.rst create mode 100644 spec/2023.12/design_topics/static_typing.rst create mode 100644 spec/2023.12/extensions/fourier_transform_functions.rst create mode 100644 spec/2023.12/extensions/index.rst create mode 100644 spec/2023.12/extensions/linear_algebra_functions.rst create mode 100644 spec/2023.12/future_API_evolution.md create mode 100644 spec/2023.12/index.rst create mode 100644 spec/2023.12/license.rst create mode 100644 spec/2023.12/purpose_and_scope.md create mode 100644 spec/2023.12/usage_data.md create mode 100644 spec/2023.12/use_cases.md create mode 100644 spec/2023.12/verification_test_suite.md create mode 100644 src/.DS_Store create mode 100644 src/array_api_stubs/_2023_12/__init__.py create mode 100644 src/array_api_stubs/_2023_12/_types.py create mode 100644 src/array_api_stubs/_2023_12/array_object.py create mode 100644 src/array_api_stubs/_2023_12/constants.py create mode 100644 src/array_api_stubs/_2023_12/creation_functions.py create mode 100644 src/array_api_stubs/_2023_12/data_type_functions.py create mode 100644 src/array_api_stubs/_2023_12/data_types.py create mode 100644 src/array_api_stubs/_2023_12/elementwise_functions.py create mode 100644 src/array_api_stubs/_2023_12/fft.py create mode 100644 src/array_api_stubs/_2023_12/indexing_functions.py create mode 100644 src/array_api_stubs/_2023_12/info.py create mode 100644 src/array_api_stubs/_2023_12/linalg.py create mode 100644 src/array_api_stubs/_2023_12/linear_algebra_functions.py create mode 100644 src/array_api_stubs/_2023_12/manipulation_functions.py create mode 100644 src/array_api_stubs/_2023_12/searching_functions.py create mode 100644 src/array_api_stubs/_2023_12/set_functions.py create mode 100644 src/array_api_stubs/_2023_12/sorting_functions.py create mode 100644 src/array_api_stubs/_2023_12/statistical_functions.py create mode 100644 src/array_api_stubs/_2023_12/utility_functions.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..cb2845bfd45fe0b2d4e5d60af22acccb797086ac GIT binary patch literal 6148 zcmeH~F$w}f3`G;&V!>uh%V|7-Hy9Q@ffo=|Y(z!TdXDZ-CJ3(9BJu;tpJXO1`-+{7 zh-iP?&P6&AY2l_avoJ74-pEzXvXjkybvYhR$31FRAH`W)!#f%5$2NroNPq-LfCNb3 zhX~lc4QnS=8A*TyNZ?7pz7Gj*nnO!f|8yYu2mozRcEj3d323qcG>4X|sK7L)2aQ(s zF~sWL4oz_`hnA|fT{MOdjVG&3F)*#|q6rC1vkLuHq@&4g1L!&>UK-q5|WOfMZ}Ffv*yH E03NCmz5oCK literal 0 HcmV?d00001 diff --git a/LICENSE b/LICENSE index e861ffccf..fb491e886 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2022 Consortium for Python Data API Standards contributors +Copyright (c) 2020-2024 Consortium for Python Data API Standards contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index d23e05218..51e1fbf76 100644 --- a/Makefile +++ b/Makefile @@ -23,5 +23,6 @@ spec: touch "$(BUILDDIR)/.nojekyll" sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) - cp -r "$(BUILDDIR)/2022.12" "$(BUILDDIR)/latest" + sphinx-build "$(SOURCEDIR)/2023.12" "$(BUILDDIR)/2023.12" $(SPHINXOPTS) + cp -r "$(BUILDDIR)/2023.12" "$(BUILDDIR)/latest" sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/spec/2023.12/API_specification/array_object.rst b/spec/2023.12/API_specification/array_object.rst new file mode 100644 index 000000000..f8a586ade --- /dev/null +++ b/spec/2023.12/API_specification/array_object.rst @@ -0,0 +1,308 @@ +.. _array-object: + +Array object +============ + + Array API specification for array object attributes and methods. + +A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods. + +Furthermore, a conforming implementation of the array API standard must support, at minimum, array objects of rank (i.e., number of dimensions) ``0``, ``1``, ``2``, ``3``, and ``4`` and must explicitly document their maximum supported rank ``N``. + +.. note:: + Conforming implementations must support zero-dimensional arrays. + + Apart from array object attributes, such as ``ndim``, ``device``, and ``dtype``, all operations in this standard return arrays (or tuples of arrays), including those operations, such as ``mean``, ``var``, and ``std``, from which some common array libraries (e.g., NumPy) return scalar values. + + *Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value.* + +------------------------------------------------- + +.. _operators: + +Operators +--------- + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. + +Arithmetic Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. + +- ``+x``: :meth:`.array.__pos__` + + - `operator.pos(x) `_ + - `operator.__pos__(x) `_ + +- `-x`: :meth:`.array.__neg__` + + - `operator.neg(x) `_ + - `operator.__neg__(x) `_ + +- `x1 + x2`: :meth:`.array.__add__` + + - `operator.add(x1, x2) `_ + - `operator.__add__(x1, x2) `_ + +- `x1 - x2`: :meth:`.array.__sub__` + + - `operator.sub(x1, x2) `_ + - `operator.__sub__(x1, x2) `_ + +- `x1 * x2`: :meth:`.array.__mul__` + + - `operator.mul(x1, x2) `_ + - `operator.__mul__(x1, x2) `_ + +- `x1 / x2`: :meth:`.array.__truediv__` + + - `operator.truediv(x1,x2) `_ + - `operator.__truediv__(x1, x2) `_ + +- `x1 // x2`: :meth:`.array.__floordiv__` + + - `operator.floordiv(x1, x2) `_ + - `operator.__floordiv__(x1, x2) `_ + +- `x1 % x2`: :meth:`.array.__mod__` + + - `operator.mod(x1, x2) `_ + - `operator.__mod__(x1, x2) `_ + +- `x1 ** x2`: :meth:`.array.__pow__` + + - `operator.pow(x1, x2) `_ + - `operator.__pow__(x1, x2) `_ + +Arithmetic operators should be defined for arrays having real-valued data types. + +Array Operators +~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. + +- `x1 @ x2`: :meth:`.array.__matmul__` + + - `operator.matmul(x1, x2) `_ + - `operator.__matmul__(x1, x2) `_ + +The matmul ``@`` operator should be defined for arrays having real-valued data types. + +Bitwise Operators +~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. + +- `~x`: :meth:`.array.__invert__` + + - `operator.inv(x) `_ + - `operator.invert(x) `_ + - `operator.__inv__(x) `_ + - `operator.__invert__(x) `_ + +- `x1 & x2`: :meth:`.array.__and__` + + - `operator.and(x1, x2) `_ + - `operator.__and__(x1, x2) `_ + +- `x1 | x2`: :meth:`.array.__or__` + + - `operator.or(x1, x2) `_ + - `operator.__or__(x1, x2) `_ + +- `x1 ^ x2`: :meth:`.array.__xor__` + + - `operator.xor(x1, x2) `_ + - `operator.__xor__(x1, x2) `_ + +- `x1 << x2`: :meth:`.array.__lshift__` + + - `operator.lshift(x1, x2) `_ + - `operator.__lshift__(x1, x2) `_ + +- `x1 >> x2`: :meth:`.array.__rshift__` + + - `operator.rshift(x1, x2) `_ + - `operator.__rshift__(x1, x2) `_ + +Bitwise operators should be defined for arrays having integer and boolean data types. + +Comparison Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. + +- `x1 < x2`: :meth:`.array.__lt__` + + - `operator.lt(x1, x2) `_ + - `operator.__lt__(x1, x2) `_ + +- `x1 <= x2`: :meth:`.array.__le__` + + - `operator.le(x1, x2) `_ + - `operator.__le__(x1, x2) `_ + +- `x1 > x2`: :meth:`.array.__gt__` + + - `operator.gt(x1, x2) `_ + - `operator.__gt__(x1, x2) `_ + +- `x1 >= x2`: :meth:`.array.__ge__` + + - `operator.ge(x1, x2) `_ + - `operator.__ge__(x1, x2) `_ + +- `x1 == x2`: :meth:`.array.__eq__` + + - `operator.eq(x1, x2) `_ + - `operator.__eq__(x1, x2) `_ + +- `x1 != x2`: :meth:`.array.__ne__` + + - `operator.ne(x1, x2) `_ + - `operator.__ne__(x1, x2) `_ + +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + +In-place Operators +~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. + +An in-place operation must not change the data type or shape of the in-place array as a result of :ref:`type-promotion` or :ref:`broadcasting`. + +An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1 = x1 + x2``. + +.. note:: + In-place operators must be supported as discussed in :ref:`copyview-mutability`. + +Arithmetic Operators +"""""""""""""""""""" + +- ``+=``. May be implemented via ``__iadd__``. +- ``-=``. May be implemented via ``__isub__``. +- ``*=``. May be implemented via ``__imul__``. +- ``/=``. May be implemented via ``__itruediv__``. +- ``//=``. May be implemented via ``__ifloordiv__``. +- ``**=``. May be implemented via ``__ipow__``. +- ``%=``. May be implemented via ``__imod__``. + +Array Operators +""""""""""""""" + +- ``@=``. May be implemented via ``__imatmul__``. + +Bitwise Operators +""""""""""""""""" + +- ``&=``. May be implemented via ``__iand__``. +- ``|=``. May be implemented via ``__ior__``. +- ``^=``. May be implemented via ``__ixor__``. +- ``<<=``. May be implemented via ``__ilshift__``. +- ``>>=``. May be implemented via ``__irshift__``. + +Reflected Operators +~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. + +The results of applying reflected operators must match their non-reflected equivalents. + +.. note:: + All operators for which ``array scalar`` is implemented must have an equivalent reflected operator implementation. + +Arithmetic Operators +"""""""""""""""""""" + +- ``__radd__`` +- ``__rsub__`` +- ``__rmul__`` +- ``__rtruediv__`` +- ``__rfloordiv__`` +- ``__rpow__`` +- ``__rmod__`` + +Array Operators +""""""""""""""" + +- ``__rmatmul__`` + +Bitwise Operators +""""""""""""""""" + +- ``__rand__`` +- ``__ror__`` +- ``__rxor__`` +- ``__rlshift__`` +- ``__rrshift__`` + +------------------------------------------------- + +.. currentmodule:: array_api + +Attributes +---------- +.. + NOTE: please keep the attributes in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.dtype + array.device + array.mT + array.ndim + array.shape + array.size + array.T + +------------------------------------------------- + +Methods +------- +.. + NOTE: please keep the methods in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.__abs__ + array.__add__ + array.__and__ + array.__array_namespace__ + array.__bool__ + array.__complex__ + array.__dlpack__ + array.__dlpack_device__ + array.__eq__ + array.__float__ + array.__floordiv__ + array.__ge__ + array.__getitem__ + array.__gt__ + array.__index__ + array.__int__ + array.__invert__ + array.__le__ + array.__lshift__ + array.__lt__ + array.__matmul__ + array.__mod__ + array.__mul__ + array.__ne__ + array.__neg__ + array.__or__ + array.__pos__ + array.__pow__ + array.__rshift__ + array.__setitem__ + array.__sub__ + array.__truediv__ + array.__xor__ + array.to_device diff --git a/spec/2023.12/API_specification/broadcasting.rst b/spec/2023.12/API_specification/broadcasting.rst new file mode 100644 index 000000000..abb3ed222 --- /dev/null +++ b/spec/2023.12/API_specification/broadcasting.rst @@ -0,0 +1,128 @@ +.. _broadcasting: + +Broadcasting +============ + + Array API specification for broadcasting semantics. + +Overview +-------- + +**Broadcasting** refers to the automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +Broadcasting facilitates user ergonomics by encouraging users to avoid unnecessary copying of array data and can **potentially** enable more memory-efficient element-wise operations through vectorization, reduced memory consumption, and cache locality. + +Algorithm +--------- + +Given an element-wise operation involving two compatible arrays, an array having a singleton dimension (i.e., a dimension whose size is one) is broadcast (i.e., virtually repeated) across an array having a corresponding non-singleton dimension. + +If two arrays are of unequal rank, the array having a lower rank is promoted to a higher rank by (virtually) prepending singleton dimensions until the number of dimensions matches that of the array having a higher rank. + +The results of the element-wise operation must be stored in an array having a shape determined by the following algorithm. + +#. Let ``A`` and ``B`` both be arrays. + +#. Let ``shape1`` be a tuple describing the shape of array ``A``. + +#. Let ``shape2`` be a tuple describing the shape of array ``B``. + +#. Let ``N1`` be the number of dimensions of array ``A`` (i.e., the result of ``len(shape1)``). + +#. Let ``N2`` be the number of dimensions of array ``B`` (i.e., the result of ``len(shape2)``). + +#. Let ``N`` be the maximum value of ``N1`` and ``N2`` (i.e., the result of ``max(N1, N2)``). + +#. Let ``shape`` be a temporary list of length ``N`` for storing the shape of the result array. + +#. Let ``i`` be ``N-1``. + +#. Repeat, while ``i >= 0`` + + #. Let ``n1`` be ``N1 - N + i``. + + #. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. + + #. Let ``n2`` be ``N2 - N + i``. + + #. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. + + #. If ``d1 == 1``, then set the ``i``\th element of ``shape`` to ``d2``. + + #. Else, if ``d2 == 1``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, if ``d1 == d2``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, throw an exception. + + #. Set ``i`` to ``i-1``. + +#. Let ``tuple(shape)`` be the shape of the result array. + +Examples +~~~~~~~~ + +The following examples demonstrate the application of the broadcasting algorithm for two compatible arrays. + +:: + + A (4d array): 8 x 1 x 6 x 1 + B (3d array): 7 x 1 x 5 + --------------------------------- + Result (4d array): 8 x 7 x 6 x 5 + A (2d array): 5 x 4 + B (1d array): 1 + ------------------------- + Result (2d array): 5 x 4 + A (2d array): 5 x 4 + B (1d array): 4 + ------------------------- + Result (2d array): 5 x 4 + A (3d array): 15 x 3 x 5 + B (3d array): 15 x 1 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 1 + ------------------------------ + Result (3d array): 15 x 3 x 5 + + +The following examples demonstrate array shapes which do **not** broadcast. + +:: + + A (1d array): 3 + B (1d array): 4 # dimension does not match + + A (2d array): 2 x 1 + B (3d array): 8 x 4 x 3 # second dimension does not match + + A (3d array): 15 x 3 x 5 + B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended + +In-place Semantics +------------------ + +As implied by the broadcasting algorithm, in-place element-wise operations (including ``__setitem__``) must not change the shape of the in-place array as a result of broadcasting. Such operations should only be supported in the case where the right-hand operand can broadcast to the shape of the left-hand operand, after any indexing operations are performed. + +For example: + +:: + + x = empty((2, 3, 4)) + a = empty((1, 3, 4)) + + # This is OK. The shape of a, (1, 3, 4), can broadcast to the shape of x[...], (2, 3, 4) + x[...] = a + + # This is not allowed. The shape of a, (1, 3, 4), can NOT broadcast to the shape of x[1, ...], (3, 4) + x[1, ...] = a diff --git a/spec/2023.12/API_specification/constants.rst b/spec/2023.12/API_specification/constants.rst new file mode 100644 index 000000000..71cb8688d --- /dev/null +++ b/spec/2023.12/API_specification/constants.rst @@ -0,0 +1,26 @@ +Constants +========= + + Array API specification for constants. + +A conforming implementation of the array API standard must provide and support the following constants adhering to the following conventions. + +- Each constant must have a Python floating-point data type (i.e., ``float``) and be provided as a Python scalar value. + +Objects in API +-------------- + +.. currentmodule:: array_api.constants + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + + e + inf + nan + newaxis + pi diff --git a/spec/2023.12/API_specification/creation_functions.rst b/spec/2023.12/API_specification/creation_functions.rst new file mode 100644 index 000000000..ff5c06368 --- /dev/null +++ b/spec/2023.12/API_specification/creation_functions.rst @@ -0,0 +1,36 @@ +Creation Functions +================== + + Array API specification for creating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + arange + asarray + empty + empty_like + eye + from_dlpack + full + full_like + linspace + meshgrid + ones + ones_like + tril + triu + zeros + zeros_like diff --git a/spec/2023.12/API_specification/data_type_functions.rst b/spec/2023.12/API_specification/data_type_functions.rst new file mode 100644 index 000000000..d42968c7b --- /dev/null +++ b/spec/2023.12/API_specification/data_type_functions.rst @@ -0,0 +1,26 @@ +Data Type Functions +=================== + + Array API specification for data type functions. + +A conforming implementation of the array API standard must provide and support the following data type functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + astype + can_cast + finfo + iinfo + isdtype + result_type diff --git a/spec/2023.12/API_specification/data_types.rst b/spec/2023.12/API_specification/data_types.rst new file mode 100644 index 000000000..5987dd322 --- /dev/null +++ b/spec/2023.12/API_specification/data_types.rst @@ -0,0 +1,143 @@ +.. _data-types: + +Data Types +========== + + Array API specification for supported data types. + +A conforming implementation of the array API standard must provide and support +the following data types ("dtypes") in its array object, and as data type +objects in its main namespace under the specified names: + ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| dtype object | description | ++==============+============================================================================================================================================================================================+ +| bool | Boolean (``True`` or ``False``). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int8 | An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int16 | A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int32 | A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int64 | A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint8 | An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint16 | A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint32 | A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint64 | A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float32 | IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float64 | IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex64 | Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex128 | Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Data type objects must have the following methods (no attributes are required): + +.. + NOTE: please keep the functions in alphabetical order + +.. currentmodule:: array_api.data_types + +.. autosummary:: + :toctree: generated + :template: method.rst + + __eq__ + + +.. note:: + A conforming implementation of the array API standard may provide and + support additional data types beyond those described in this specification. + It may also support additional methods and attributes on dtype objects. + +.. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. + + +Use of data type objects +------------------------ + +Data type objects are used as ``dtype`` specifiers in functions and methods +(e.g., ``zeros((2, 3), dtype=float32)``), accessible as ``.dtype`` attribute on +arrays, and used in various casting and introspection functions (e.g., +``isdtype(x.dtype, 'integral')``). + +``dtype`` keywords in functions specify the data type of arrays returned from +functions or methods. ``dtype`` keywords are not required to affect the data +type used for intermediate calculations or results (e.g., implementors are free +to use a higher-precision data type when accumulating values for reductions, as +long as the returned array has the specified data type). + +.. note:: + Implementations may provide other ways to specify data types (e.g., ``zeros((2, 3), dtype='f4')``) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. + +See :ref:`type-promotion` for specification guidance describing the rules governing the interaction of two or more data types or data type objects. + + +.. _data-type-defaults: + +Default Data Types +------------------ + +A conforming implementation of the array API standard must define the following default data types. + +- a default real-valued floating-point data type (either ``float32`` or ``float64``). +- a default complex floating-point data type (either ``complex64`` or ``complex128``). +- a default integer data type (either ``int32`` or ``int64``). +- a default array index data type (either ``int32`` or ``int64``). + +The default real-valued floating-point and complex floating-point data types must be the same across platforms. + +The default complex floating-point point data type should match the default real-valued floating-point data type. For example, if the default real-valued floating-point data type is ``float32``, the default complex floating-point data type must be ``complex64``. If the default real-valued floating-point data type is ``float64``, the default complex floating-point data type must be ``complex128``. + +The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. + +The default array index data type may be ``int32`` on 32-bit platforms, but the default should be ``int64`` otherwise. + +Note that it is possible that a library supports multiple devices, with not all +those device types supporting the same data types. In this case, the default +integer or floating-point data types may vary with device. If that is the case, +the library should clearly warn about this in its documentation. + +.. note:: + The default data types should be clearly defined in a conforming library's documentation. + + +.. _data-type-categories: + +Data Type Categories +-------------------- + +For the purpose of organizing functions within this specification, the following data type categories are defined. + ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| data type category | dtypes | ++============================+========================================================================================================================================================+ +| Numeric | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Floating-point | ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued floating-point | ``float32`` and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Complex floating-point | ``complex64`` and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Boolean | ``bool``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +.. note:: + Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. diff --git a/spec/2023.12/API_specification/elementwise_functions.rst b/spec/2023.12/API_specification/elementwise_functions.rst new file mode 100644 index 000000000..4919cff98 --- /dev/null +++ b/spec/2023.12/API_specification/elementwise_functions.rst @@ -0,0 +1,84 @@ +.. _element-wise-functions: + +Element-wise Functions +====================== + + Array API specification for element-wise functions. + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + abs + acos + acosh + add + asin + asinh + atan + atan2 + atanh + bitwise_and + bitwise_left_shift + bitwise_invert + bitwise_or + bitwise_right_shift + bitwise_xor + ceil + clip + conj + copysign + cos + cosh + divide + equal + exp + expm1 + floor + floor_divide + greater + greater_equal + hypot + imag + isfinite + isinf + isnan + less + less_equal + log + log1p + log2 + log10 + logaddexp + logical_and + logical_not + logical_or + logical_xor + maximum + minimum + multiply + negative + not_equal + positive + pow + real + remainder + round + sign + signbit + sin + sinh + square + sqrt + subtract + tan + tanh + trunc diff --git a/spec/2023.12/API_specification/function_and_method_signatures.rst b/spec/2023.12/API_specification/function_and_method_signatures.rst new file mode 100644 index 000000000..0eca2ac69 --- /dev/null +++ b/spec/2023.12/API_specification/function_and_method_signatures.rst @@ -0,0 +1,63 @@ +.. _function-and-method-signatures: + +Function and method signatures +============================== + +Function signatures in this standard adhere to the following: + +1. Positional parameters should 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. + + *Rationale: existing libraries have incompatible conventions, and using names + of positional parameters is not normal/recommended practice.* + + .. note:: + + Positional-only parameters are only available in Python >= 3.8. Libraries + still supporting 3.7 or 3.6 may consider making the API standard-compliant + namespace >= 3.8. Alternatively, they can add guidance to their users in the + documentation to use the functions as if they were positional-only. + +2. Optional parameters should be `keyword-only `_ arguments. + + *Rationale: this leads to more readable code, and it makes it easier to + evolve an API over time by adding keywords without having to worry about + keyword order.* + +3. For functions that have a single positional array parameter, that parameter + is called ``x``. For functions that have multiple array parameters, those + parameters are called ``xi`` with ``i = 1, 2, ...`` (i.e., ``x1``, ``x2``). + +4. Signatures include type annotations. The type annotations are also added to + individual parameter and return value descriptions. For code which aims to + adhere to the standard, adding type annotations is strongly recommended. + +A function signature and description will look like: + +:: + + funcname(x1, x2, /, *, key1=-1, key2=None) -> out: + Parameters + + x1 : array + description + x2 : array + description + key1 : int + description + key2 : Optional[str] + description + + Returns + + out : array + description + + +Method signatures will follow the same conventions modulo the addition of ``self``. + +Note that there are a few exceptions to rules (1) and (2), in cases where +it enhances readability or use of the non-default form of the parameter in +question is commonly used in code written for existing array libraries. diff --git a/spec/2023.12/API_specification/index.rst b/spec/2023.12/API_specification/index.rst new file mode 100644 index 000000000..ffc3d3775 --- /dev/null +++ b/spec/2023.12/API_specification/index.rst @@ -0,0 +1,41 @@ +.. _api-specification: + +API specification +================= + +A conforming implementation of the array API standard must provide and support the APIs and behavior detailed in this specification while adhering to the following conventions. + +- When a function signature includes a `/`, positional parameters must be `positional-only `_ parameters. See :ref:`function-and-method-signatures`. +- When a function signature includes a `*`, optional parameters must be `keyword-only `_ arguments. See :ref:`function-and-method-signatures`. +- Broadcasting semantics must follow the semantics defined in :ref:`broadcasting`. +- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. +- Functions may only be required for a subset of input data types. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in :ref:`accuracy`. + + +.. toctree:: + :caption: API specification + :maxdepth: 3 + + array_object + broadcasting + constants + creation_functions + data_type_functions + data_types + elementwise_functions + function_and_method_signatures + indexing + indexing_functions + inspection + linear_algebra_functions + manipulation_functions + searching_functions + set_functions + sorting_functions + statistical_functions + type_promotion + utility_functions + version diff --git a/spec/2023.12/API_specification/indexing.rst b/spec/2023.12/API_specification/indexing.rst new file mode 100644 index 000000000..eb61c26d5 --- /dev/null +++ b/spec/2023.12/API_specification/indexing.rst @@ -0,0 +1,208 @@ +.. _indexing: + +Indexing +======== + + Array API specification for indexing arrays. + +A conforming implementation of the array API standard must adhere to the following conventions. + +Single-axis Indexing +-------------------- + +To index a single array axis, an array must support standard Python indexing rules. Let ``n`` be the axis (dimension) size. + +- An integer index must be an object satisfying `operator.index `_ (e.g., ``int``). + +- Nonnegative indices must start at ``0`` (i.e., zero-based indexing). + +- **Valid** nonnegative indices must reside on the half-open interval ``[0, n)``. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- Negative indices must count backward from the last array index, starting from ``-1`` (i.e., negative-one-based indexing, where ``-1`` refers to the last array index). + + .. note:: + A negative index ``j`` is equivalent to ``n-j``; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. + +- **Valid** negative indices must reside on the closed interval ``[-n, -1]``. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- A negative index ``j`` is related to a zero-based nonnegative index ``i`` via ``i = n+j``. + +- Colons ``:`` must be used for `slices `_: ``start:stop:step``, where ``start`` is inclusive and ``stop`` is exclusive. + + .. note:: + The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. + +Slice Syntax +~~~~~~~~~~~~ + +The basic slice syntax is ``i:j:k`` where ``i`` is the starting index, ``j`` is the stopping index, and ``k`` is the step (``k != 0``). A slice may contain either one or two colons, with either an integer value or nothing on either side of each colon. The following are valid slices. + +:: + + A[:] + A[i:] + A[:j] + A[i:k] + A[::] + A[i::] + A[:j:] + A[::k] + A[i:j:] + A[i::k] + A[:j:k] + A[i::k] + A[i:j:k] + +.. note:: + Slice syntax can be equivalently achieved using the Python built-in `slice() `_ API. From the perspective of ``A``, the behavior of ``A[i:j:k]`` and ``A[slice(i, j, k)]`` is indistinguishable (i.e., both retrieve the same set of items from ``__getitem__``). + +Using a slice to index a single array axis must select ``m`` elements with index values + +:: + + i, i+k, i+2k, i+3k, ..., i+(m-1)k + +where + +:: + + m = q + r + +and ``q`` and ``r`` (``r != 0``) are the quotient and remainder obtained by dividing ``j-i`` by ``k`` + +:: + + j - i = qk + r + +such that + +:: + + j > i + (m-1)k + +.. note:: + For ``i`` on the interval ``[0, n)`` (where ``n`` is the axis size), ``j`` on the interval ``(0, n]``, ``i`` less than ``j``, and positive step ``k``, a starting index ``i`` is **always** included, while the stopping index ``j`` is **always** excluded. This preserves ``x[:i]+x[i:]`` always being equal to ``x``. + +.. note:: + Using a slice to index into a single array axis should select the same elements as using a slice to index a Python list of the same size. + +Slice syntax must have the following defaults. Let ``n`` be the axis (dimension) size. + +- If ``k`` is not provided (e.g., ``0:10``), ``k`` must equal ``1``. +- If ``k`` is greater than ``0`` and ``i`` is not provided (e.g., ``:10:2``), ``i`` must equal ``0``. +- If ``k`` is greater than ``0`` and ``j`` is not provided (e.g., ``0::2``), ``j`` must equal ``n``. +- If ``k`` is less than ``0`` and ``i`` is not provided (e.g., ``:10:-2``), ``i`` must equal ``n-1``. +- If ``k`` is less than ``0`` and ``j`` is not provided (e.g., ``0::-2``), ``j`` must equal ``-n-1``. + +Using a slice to index a single array axis must adhere to the following rules. Let ``n`` be the axis (dimension) size. + +- If ``i`` equals ``j``, a slice must return an empty array, whose axis (dimension) size along the indexed axis is ``0``. + +- Indexing via ``:`` and ``::`` must be equivalent and have defaults derived from the rules above. Both ``:`` and ``::`` indicate to select all elements along a single axis (dimension). + + .. note:: + This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where ``0:100`` and ``0:10`` are equivalent on a list of length ``10``. + +The following ranges for the start and stop values of a slice must be supported. Let ``n`` be the axis (dimension) size being sliced. For a slice ``i:j:k``, the behavior specified above should be implemented for the following: + +- ``i`` or ``j`` omitted (``None``). +- ``-n <= i <= n``. +- For ``k > 0`` or ``k`` omitted (``None``), ``-n <= j <= n``. +- For ``k < 0``, ``-n - 1 <= j <= max(0, n - 1)``. + +The behavior outside of these bounds is unspecified. + +.. note:: + *Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip (consistent with Python* ``list`` *slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +Multi-axis Indexing +------------------- + +Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let ``N`` be the number of dimensions ("rank") of a multi-dimensional array ``A``. + +- Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., ``A[:, 2:10, :, 5]``). + + .. note:: + In Python, ``A[(exp1, exp2, ..., expN)]`` is equivalent to ``A[exp1, exp2, ..., expN]``; the latter is syntactic sugar for the former. + + Accordingly, if ``A`` has rank ``1``, then ``A[(2:10,)]`` must be equivalent to ``A[2:10]``. If ``A`` has rank ``2``, then ``A[(2:10, :)]`` must be equivalent to ``A[2:10, :]``. And so on and so forth. + +- Providing a single nonnegative integer ``i`` as a single-axis index must index the same elements as the slice ``i:i+1``. + +- Providing a single negative integer ``i`` as a single-axis index must index the same elements as the slice ``n+i:n+i+1``, where ``n`` is the axis (dimension) size. + +- Providing a single integer as a single-axis index must reduce the number of array dimensions by ``1`` (i.e., the array rank must decrease by one; if ``A`` has rank ``2``, ``rank(A)-1 == rank(A[0, :])``). In particular, a selection tuple with the ``m``\th element an integer (and all other entries ``:``) indexes a sub-array with rank ``N-1``. + + .. note:: + When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. + +- Providing a slice must retain array dimensions (i.e., the array rank must remain the same; ``rank(A) == rank(A[:])``). + +- Providing `ellipsis `_ must apply ``:`` to each dimension necessary to index all dimensions (e.g., if ``A`` has rank ``4``, ``A[1:, ..., 2:5] == A[1:, :, :, 2:5]``). Only a single ellipsis must be allowed. An ``IndexError`` exception must be raised if more than one ellipsis is provided. + +- Providing an empty tuple or an ellipsis to an array of rank ``0`` must result in an array of the same rank (i.e., if ``A`` has rank ``0``, ``A == A[()]`` and ``A == A[...]``). + + .. note:: + This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. + +- Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. + + .. note:: + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. + + .. note:: + The constant ``newaxis`` is an alias of ``None`` and can thus be used in a similar manner as ``None``. + +- Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. + + .. note:: + Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. + + To perform flat indexing, use ``reshape(x, (-1,))[integer]``. + +- An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions (excluding ``None``) is greater than ``N``. + + .. note:: + This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. + + *Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to* ``0`` *, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +Boolean Array Indexing +---------------------- + +.. admonition:: Data-dependent output shape + :class: admonition important + + For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See :ref:`data-dependent-output-shapes` section for more details. + +An array must support indexing where the **sole index** is an ``M``-dimensional boolean array ``B`` with shape ``S1 = (s1, ..., sM)`` according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S2 = (s1, ..., sM, ..., sN)``. + + .. note:: + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~array_api.expand_dims`. + +- If ``N >= M``, then ``A[B]`` must replace the first ``M`` dimensions of ``A`` with a single dimension having a size equal to the number of ``True`` elements in ``B``. The values in the resulting array must be in row-major (C-style order); this is equivalent to ``A[nonzero(B)]``. + + .. note:: + For example, if ``N == M == 2``, indexing ``A`` via a boolean array ``B`` will return a one-dimensional array whose size is equal to the number of ``True`` elements in ``B``. + +- If ``N < M``, then an ``IndexError`` exception must be raised. + +- The size of each dimension in ``B`` must equal the size of the corresponding dimension in ``A`` or be ``0``, beginning with the first dimension in ``A``. If a dimension size does not equal the size of the corresponding dimension in ``A`` and is not ``0``, then an ``IndexError`` exception must be raised. + +- The elements of a boolean index array must be iterated in row-major, C-style order, with the exception of zero-dimensional boolean arrays. + +- A zero-dimensional boolean index array (equivalent to ``True`` or ``False``) must follow the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length ``1`` if the index array's value is ``True`` and of length ``0`` if the index array's value is ``False``. Accordingly, for a zero-dimensional boolean index array ``B``, the result of ``A[B]`` has shape ``S = (1, s1, ..., sN)`` if the index array's value is ``True`` and has shape ``S = (0, s1, ..., sN)`` if the index array's value is ``False``. + +Return Values +------------- + +The result of an indexing operation (e.g., multi-axis indexing, boolean array indexing, etc) must be an array of the same data type as the indexed array. + +.. note:: + The specified return value behavior includes indexing operations which return a single value (e.g., accessing a single element within a one-dimensional array). diff --git a/spec/2023.12/API_specification/indexing_functions.rst b/spec/2023.12/API_specification/indexing_functions.rst new file mode 100644 index 000000000..aef298566 --- /dev/null +++ b/spec/2023.12/API_specification/indexing_functions.rst @@ -0,0 +1,23 @@ +.. _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. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + take diff --git a/spec/2023.12/API_specification/inspection.rst b/spec/2023.12/API_specification/inspection.rst new file mode 100644 index 000000000..04691e712 --- /dev/null +++ b/spec/2023.12/API_specification/inspection.rst @@ -0,0 +1,40 @@ +Inspection +========== + + Array API specification for namespace inspection utilities. + +A conforming implementation of the array API standard must provide and support the following functions and associated inspection APIs. + + +Objects in API +-------------- + +.. currentmodule:: array_api.info + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + __array_namespace_info__ + + +Inspection APIs +--------------- + +In the namespace (or class) returned by ``__array_namespace_info__``, a conforming implementation of the array API standard must provide and support the following functions (or methods) for programmatically querying data type and device support, capabilities, and other specification-defined implementation-specific behavior, as documented in the functions described below. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + capabilities + default_device + default_dtypes + devices + dtypes diff --git a/spec/2023.12/API_specification/linear_algebra_functions.rst b/spec/2023.12/API_specification/linear_algebra_functions.rst new file mode 100644 index 000000000..04d36f50a --- /dev/null +++ b/spec/2023.12/API_specification/linear_algebra_functions.rst @@ -0,0 +1,23 @@ +Linear Algebra Functions +======================== + + Array API specification for linear algebra functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + matmul + matrix_transpose + tensordot + vecdot diff --git a/spec/2023.12/API_specification/manipulation_functions.rst b/spec/2023.12/API_specification/manipulation_functions.rst new file mode 100644 index 000000000..395c1c3e2 --- /dev/null +++ b/spec/2023.12/API_specification/manipulation_functions.rst @@ -0,0 +1,34 @@ +Manipulation Functions +====================== + + Array API specification for manipulating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + broadcast_arrays + broadcast_to + concat + expand_dims + flip + moveaxis + permute_dims + repeat + reshape + roll + squeeze + stack + tile + unstack diff --git a/spec/2023.12/API_specification/searching_functions.rst b/spec/2023.12/API_specification/searching_functions.rst new file mode 100644 index 000000000..c952f1aad --- /dev/null +++ b/spec/2023.12/API_specification/searching_functions.rst @@ -0,0 +1,27 @@ +.. _searching-functions: + +Searching Functions +=================== + + Array API specification for functions for searching arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argmax + argmin + nonzero + searchsorted + where diff --git a/spec/2023.12/API_specification/set_functions.rst b/spec/2023.12/API_specification/set_functions.rst new file mode 100644 index 000000000..addf31e1f --- /dev/null +++ b/spec/2023.12/API_specification/set_functions.rst @@ -0,0 +1,24 @@ +Set Functions +============= + + Array API specification for creating and operating on sets. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + unique_all + unique_counts + unique_inverse + unique_values diff --git a/spec/2023.12/API_specification/sorting_functions.rst b/spec/2023.12/API_specification/sorting_functions.rst new file mode 100644 index 000000000..ad3af8857 --- /dev/null +++ b/spec/2023.12/API_specification/sorting_functions.rst @@ -0,0 +1,31 @@ +Sorting Functions +================= + + Array API specification for sorting functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. note:: + + For floating-point input arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. + + Implementations may choose to sort signed zeros (``-0 < +0``) or may choose to rely solely on value equality (``==``). + + Implementations may choose to sort NaNs (e.g., to the end or to the beginning of a returned array) or leave them in-place. Should an implementation sort NaNs, the sorting convention should be clearly documented in the conforming implementation's documentation. + + While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argsort + sort diff --git a/spec/2023.12/API_specification/statistical_functions.rst b/spec/2023.12/API_specification/statistical_functions.rst new file mode 100644 index 000000000..20e02b3f9 --- /dev/null +++ b/spec/2023.12/API_specification/statistical_functions.rst @@ -0,0 +1,28 @@ +Statistical Functions +===================== + + Array API specification for statistical functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cumulative_sum + max + mean + min + prod + std + sum + var diff --git a/spec/2023.12/API_specification/type_promotion.rst b/spec/2023.12/API_specification/type_promotion.rst new file mode 100644 index 000000000..339b90e45 --- /dev/null +++ b/spec/2023.12/API_specification/type_promotion.rst @@ -0,0 +1,148 @@ +.. _type-promotion: + +Type Promotion Rules +==================== + + Array API specification for type promotion rules. + +Type promotion rules can be understood at a high level from the following diagram: + +.. image:: ../../_static/images/dtype_promotion_lattice.png + :target: Type promotion diagram + +*Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* + +Rules +----- + +A conforming implementation of the array API standard must implement the following type promotion rules governing the common result type for two **array** operands during an arithmetic operation. + +A conforming implementation of the array API standard may support additional type promotion rules beyond those described in this specification. + +.. note:: + Type codes are used here to keep tables readable; they are not part of the standard. In code, use the data type objects specified in :ref:`data-types` (e.g., ``int16`` rather than ``'i2'``). + +.. + Note: please keep table columns aligned + +The following type promotion tables specify the casting behavior for operations involving two array operands. When more than two array operands participate, application of the promotion tables is associative (i.e., the result does not depend on operand order). + +Signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | i1 | i2 | i4 | i8 | ++========+====+====+====+====+ +| **i1** | i1 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i2** | i2 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i4** | i4 | i4 | i4 | i8 | ++--------+----+----+----+----+ +| **i8** | i8 | i8 | i8 | i8 | ++--------+----+----+----+----+ + +where + +- **i1**: 8-bit signed integer (i.e., ``int8``) +- **i2**: 16-bit signed integer (i.e., ``int16``) +- **i4**: 32-bit signed integer (i.e., ``int32``) +- **i8**: 64-bit signed integer (i.e., ``int64``) + +Unsigned integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | u1 | u2 | u4 | u8 | ++========+====+====+====+====+ +| **u1** | u1 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u2** | u2 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u4** | u4 | u4 | u4 | u8 | ++--------+----+----+----+----+ +| **u8** | u8 | u8 | u8 | u8 | ++--------+----+----+----+----+ + +where + +- **u1**: 8-bit unsigned integer (i.e., ``uint8``) +- **u2**: 16-bit unsigned integer (i.e., ``uint16``) +- **u4**: 32-bit unsigned integer (i.e., ``uint32``) +- **u8**: 64-bit unsigned integer (i.e., ``uint64``) + +Mixed unsigned and signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+ +| | u1 | u2 | u4 | ++========+====+====+====+ +| **i1** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i2** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i4** | i4 | i4 | i8 | ++--------+----+----+----+ +| **i8** | i8 | i8 | i8 | ++--------+----+----+----+ + +Floating-point type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++---------+-----+-----+-----+-----+ +| | f4 | f8 | c8 | c16 | ++=========+=====+=====+=====+=====+ +| **f4** | f4 | f8 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **f8** | f8 | f8 | c16 | c16 | ++---------+-----+-----+-----+-----+ +| **c8** | c8 | c16 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **c16** | c16 | c16 | c16 | c16 | ++---------+-----+-----+-----+-----+ + +where + +- **f4**: single-precision (32-bit) floating-point number (i.e., ``float32``) +- **f8**: double-precision (64-bit) floating-point number (i.e., ``float64``) +- **c8**: single-precision complex floating-point number (i.e., ``complex64``) + composed of two single-precision (32-bit) floating-point numbers +- **c16**: double-precision complex floating-point number (i.e., ``complex128``) + composed of two double-precision (64-bit) floating-point numbers + + +Notes +~~~~~ + +- Type promotion rules must apply when determining the common result type for two **array** operands during an arithmetic operation, regardless of array dimension. Accordingly, zero-dimensional arrays must be subject to the same type promotion rules as dimensional arrays. +- Type promotion of non-numerical data types to numerical data types is unspecified (e.g., ``bool`` to ``intxx`` or ``floatxx``). + +.. note:: + Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. + +Mixing arrays with Python scalars +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using Python scalars (i.e., instances of ``bool``, ``int``, ``float``, ``complex``) together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with the array data type: + +- a Python ``bool`` for a ``bool`` array data type. +- a Python ``int`` within the bounds of the given data type for integer array :ref:`data-types`. +- a Python ``int`` or ``float`` for real-valued floating-point array data types. +- a Python ``int``, ``float``, or ``complex`` for complex floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to zero-dimensional array with the same data type as that of the array used in the expression. +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +.. note:: + Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. + + Similarly, behavior is not specified when mixing a Python ``complex`` and an array with a real-valued data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. + + Behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. diff --git a/spec/2023.12/API_specification/utility_functions.rst b/spec/2023.12/API_specification/utility_functions.rst new file mode 100644 index 000000000..5105fa3df --- /dev/null +++ b/spec/2023.12/API_specification/utility_functions.rst @@ -0,0 +1,22 @@ +Utility Functions +================= + + Array API specification for utility functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + all + any diff --git a/spec/2023.12/API_specification/version.rst b/spec/2023.12/API_specification/version.rst new file mode 100644 index 000000000..346395d9a --- /dev/null +++ b/spec/2023.12/API_specification/version.rst @@ -0,0 +1,22 @@ +Version +======= + + Array API specification for versioning. + +A conforming implementation of the array API standard must provide a `__array_api_version__` attribute - see :ref:`api-versioning` for details. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + :nosignatures: + + __array_api_version__ diff --git a/spec/2023.12/assumptions.md b/spec/2023.12/assumptions.md new file mode 100644 index 000000000..b11482c5a --- /dev/null +++ b/spec/2023.12/assumptions.md @@ -0,0 +1,77 @@ +(Assumptions)= + +# Assumptions + +## Hardware and software environments + +No assumptions on a specific hardware environment are made. It must be possible +to create an array library adhering to this standard that runs (efficiently) on +a variety of different hardware: CPUs with different architectures, GPUs, +distributed systems and TPUs and other emerging accelerators. + +The same applies to software environments: it must be possible to create an +array library adhering to this standard that runs efficiently independent of +what compilers, build-time or run-time execution environment, or distribution +and install method is employed. Parallel execution, JIT compilation, and +delayed (lazy) evaluation must all be possible. + +The variety of hardware and software environments puts _constraints_ on choices +made in the API standard. For example, JIT compilers may require output dtypes +of functions to be predictable from input dtypes only rather than input values. + + +(assumptions-dependencies)= + +## Dependencies + +The only dependency that's assumed in this standard is that on Python itself. +Python >= 3.8 is assumed, motivated by the use of positional-only parameters +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). + +Importantly, array libraries are not assumed to be aware of each other, or of +a common array-specific layer. The [use cases](use_cases.md) do not require +such a dependency, and building and evolving an array library is easier without +such a coupling. Facilitation support of multiple array types in downstream +libraries is an important use case however, the assumed dependency structure +for that is: + +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) + +Array libraries may know how to interoperate with each other, for example by +constructing their own array type from that of another library or by shared +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). +This can be done without a dependency though - only adherence to a protocol is +enough. + +Array-consuming libraries will have to depend on one or more array libraries. +That could be a "soft dependency" though, meaning retrieving an array library +namespace from array instances that are passed in, but not explicitly doing +`import arraylib_name`. + + +## Backwards compatibility + +The assumption made during creation of this standard is that libraries are +constrained by backwards compatibility guarantees to their users, and are +likely unwilling to make significant backwards-incompatible changes for the +purpose of conforming to this standard. Therefore it is assumed that the +standard will be made available in a new namespace within each library, or the +library will provide a way to retrieve a module or module-like object that +adheres to this standard. See {ref}`how-to-adopt-this-api` for more details. + + +## Production code & interactive use + +It is assumed that the primary use case is writing production code, for example +in array-consuming libraries. As a consequence, making it easy to ensure that +code is written as intended and has unambiguous semantics is preferred - and +clear exceptions must be raised otherwise. + +It is also assumed that this does not significantly detract from the +interactive user experience. However, in case existing libraries differ in +behavior, the more strict version of that behavior is typically preferred. A +good example is array inputs to functions - while NumPy accepts lists, tuples, +generators, and anything else that could be turned into an array, most other +libraries only accept their own array types. This standard follows the latter choice. +It is likely always possible to put a thin "interactive use convenience layer" +on top of a more strict behavior. diff --git a/spec/2023.12/benchmark_suite.md b/spec/2023.12/benchmark_suite.md new file mode 100644 index 000000000..41066c6a4 --- /dev/null +++ b/spec/2023.12/benchmark_suite.md @@ -0,0 +1,3 @@ +# Benchmark suite + +Adding a benchmark suite is planned in the future. diff --git a/spec/2023.12/changelog.rst b/spec/2023.12/changelog.rst new file mode 100644 index 000000000..701a3dbcd --- /dev/null +++ b/spec/2023.12/changelog.rst @@ -0,0 +1,5 @@ +Changelog per API standard version +================================== + +.. include:: ../../CHANGELOG.md + :parser: myst_parser.sphinx_ diff --git a/spec/2023.12/conf.py b/spec/2023.12/conf.py new file mode 100644 index 000000000..f1bee91d4 --- /dev/null +++ b/spec/2023.12/conf.py @@ -0,0 +1,13 @@ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) + +from array_api_stubs import _2023_12 as stubs_mod +from _array_api_conf import * + +release = "2023.12" + +nav_title = html_theme_options.get("nav_title") + " v{}".format(release) +html_theme_options.update({"nav_title": nav_title}) +sys.modules["array_api"] = stubs_mod diff --git a/spec/2023.12/design_topics/C_API.rst b/spec/2023.12/design_topics/C_API.rst new file mode 100644 index 000000000..6a44596b0 --- /dev/null +++ b/spec/2023.12/design_topics/C_API.rst @@ -0,0 +1,94 @@ +.. _C-API: + +C API +===== + +Use of a C API is out of scope for this array API, as mentioned in :ref:`Scope`. +There are a lot of libraries that do use such an API - in particular via Cython code +or via direct usage of the NumPy C API. When the maintainers of such libraries +want to use this array API standard to support multiple types of arrays, they +need a way to deal with that issue. This section aims to provide some guidance. + +The assumption in the rest of this section is that performance matters for the library, +and hence the goal is to make other array types work without converting to a +``numpy.ndarray`` or another particular array type. If that's not the case (e.g. for a +visualization package), then other array types can simply be handled by converting +to the supported array type. + +.. note:: + Often a zero-copy conversion to ``numpy.ndarray`` is possible, at least for CPU arrays. + If that's the case, this may be a good way to support other array types. + The main difficulty in that case will be getting the return array type right - however, + this standard does provide a Python-level API for array construction that should allow + doing this. A relevant question is if it's possible to know with + certainty that a conversion will be zero-copy. This may indeed be + possible, see :ref:`data-interchange`. + + +Example situations for C/Cython usage +------------------------------------- + +Situation 1: a Python package that is mostly pure Python, with a limited number of Cython extensions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include Statsmodels, scikit-bio and QuTiP + +Main strategy: documentation. The functionality using Cython code will not support other array types (or only with conversion to/from ``numpy.ndarray``), which can be documented per function. + + +Situation 2: a Python package that contains a lot of Cython code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include scikit-learn and scikit-image + +Main strategy: add support for other array types *per submodule*. This keeps it manageable to explain to the user which functionality does and doesn't have support. + +Longer term: specific support for particular array types (e.g. ``cupy.ndarray`` can be supported with Python-only code via ``cupy.ElementwiseKernel``). + + +Situation 3: a Python package that uses the NumPy or Python C API directly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include SciPy and Astropy + +Strategy: similar to *situation 2*, but the number of submodules that can support all array types may be limited. + + +Device support +-------------- + +Supporting non-CPU array types in code using the C API or Cython seems problematic, +this almost inevitably will require custom device-specific code (e.g., CUDA, ROCm) or +something like JIT compilation with Numba. + + +Other longer-term approaches +---------------------------- + +Further Python API standardization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There may be cases where it makes sense to standardize additional sets of +functions, because they're important enough that array libraries tend to +reimplement them. An example of this may be *special functions*, as provided +by ``scipy.special``. Bessel and gamma functions for example are commonly +reimplemented by array libraries. This may avoid having to drop into a +particular implementation that does use a C API (e.g., one can then rely on +``arraylib.special.gamma`` rather than having to use ``scipy.special.gamma``). + +HPy +~~~ + +`HPy `_ is a new project that will provide a higher-level +C API and ABI than CPython offers. A Cython backend targeting HPy will be provided as well. + +- Better PyPy support +- Universal ABI - single binary for all supported Python versions +- Cython backend generating HPy rather than CPython code + +HPy isn't quite ready for mainstream usage today, but once it is it may +help make supporting multiple array libraries or adding non-CPU device +support to Cython more feasible. diff --git a/spec/2023.12/design_topics/accuracy.rst b/spec/2023.12/design_topics/accuracy.rst new file mode 100644 index 000000000..8c97db698 --- /dev/null +++ b/spec/2023.12/design_topics/accuracy.rst @@ -0,0 +1,77 @@ +.. _accuracy: + +Accuracy +======== + + Array API specification for minimum accuracy requirements. + +Arithmetic Operations +--------------------- + +The results of element-wise arithmetic operations + +- ``+`` +- ``-`` +- ``*`` +- ``/`` +- ``%`` + +including the corresponding element-wise array APIs defined in this standard + +- add +- subtract +- multiply +- divide + +for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., ties rounded toward the nearest value with an even least significant bit). + +Mathematical Functions +---------------------- + +This specification does **not** precisely define the behavior of the following functions + +- acos +- acosh +- asin +- asinh +- atan +- atan2 +- atanh +- cos +- cosh +- exp +- expm1 +- log +- log1p +- log2 +- log10 +- pow +- sin +- sinh +- tan +- tanh + +except to require specific results for certain argument values that represent boundary cases of interest. + +.. note:: + To help readers identify functions lacking precisely defined accuracy behavior, this specification uses the phrase "implementation-dependent approximation" in function descriptions. + +For other argument values, these functions should compute approximations to the results of respective mathematical functions; however, this specification recognizes that array libraries may be constrained by underlying hardware and/or seek to optimize performance over absolute accuracy and, thus, allows some latitude in the choice of approximation algorithms. + +Although the specification leaves the choice of algorithms to the implementation, this specification recommends (but does not specify) that implementations use the approximation algorithms for IEEE 754-2019 arithmetic contained in `FDLIBM `_, the freely distributable mathematical library from Sun Microsystems, or some other comparable IEEE 754-2019 compliant mathematical library. + +.. note:: + With exception of a few mathematical functions, returning results which are indistinguishable from correctly rounded infinitely precise results is difficult, if not impossible, to achieve due to the algorithms involved, the limits of finite-precision, and error propagation. However, this specification recognizes that numerical accuracy alignment among array libraries is desirable in order to ensure portability and reproducibility. Accordingly, for each mathematical function, the specification test suite includes test values which span a function's domain and reports the average and maximum deviation from either a designated standard implementation (e.g., an arbitrary precision arithmetic implementation) or an average computed across a subset of known array library implementations. Such reporting aids users who need to know how accuracy varies among libraries and developers who need to check the validity of their implementations. + +Statistical Functions +--------------------- + +This specification does not specify accuracy requirements for statistical functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +.. note:: + In order for an array library to pass the specification test suite, an array library's statistical function implementations must satisfy certain bare-minimum accuracy requirements (e.g., accurate summation of a small set of positive integers). Unfortunately, imposing more rigorous accuracy requirements is not possible without severely curtailing possible implementation algorithms and unduly increasing implementation complexity. + +Linear Algebra +-------------- + +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2023.12/design_topics/complex_numbers.rst b/spec/2023.12/design_topics/complex_numbers.rst new file mode 100644 index 000000000..0eca79e91 --- /dev/null +++ b/spec/2023.12/design_topics/complex_numbers.rst @@ -0,0 +1,61 @@ +.. _complex-numbers: + +Complex Numbers +=============== + +The Complex Plane +----------------- + +Mathematically, equality comparison between complex numbers depends on the choice of topology. For example, the complex plane has a continuum of infinities; however, when the complex plane is projected onto the surface of a sphere (a stereographic projection commonly referred to as the *Riemann sphere*), infinities coalesce into a single *point at infinity*, thus modeling the extended complex plane. For the former, the value :math:`\infty + 3j` is distinct from (i.e., does not equal) :math:`\infty + 4j`, while, for the latter, :math:`\infty + 3j` does equal :math:`\infty + 4j`. + +Modeling complex numbers as a Riemann sphere conveys certain mathematical niceties (e.g., well-behaved division by zero and preservation of the identity :math:`\frac{1}{\frac{1}{z}} = z`); however, translating the model to IEEE 754 floating-point operations can lead to some unexpected results. For example, according to IEEE 754, :math:`+\infty` and :math:`-\infty` are distinct values; hence, for equality comparison, if :math:`x = +\infty` and :math:`y = -\infty`, then :math:`x \neq y`. In contrast, if we convert :math:`x` and :math:`y` to their complex number equivalents :math:`x = +\infty + 0j` and :math:`y = -\infty + 0j` and then interpret within the context of the extended complex plane, we arrive at the opposite result; namely, :math:`x = y`. + +In short, given the constraints of floating-point arithmetic and the subtleties of signed zeros, infinities, NaNs, and their interaction, crafting a specification which always yields intuitive results and satisfies all use cases involving complex numbers is not possible. Instead, this specification attempts to follow precedent (e.g., C99, Python, Julia, NumPy, and elsewhere), while also minimizing surprise. The result is an imperfect balance in which certain APIs may appear to embrace the one-infinity model found in C/C++ for algebraic operations involving complex numbers (e.g., considering :math:`\infty + \operatorname{NaN}\ j` to be infinite, irrespective of the imaginary component's value, including NaN), while other APIs may rely on the complex plane with its multiplicity of infinities (e.g., in transcendental functions). Accordingly, consumers of this specification should expect that certain results involving complex numbers for one operation may not be wholly consistent with results involving complex numbers for another operation. + + +.. _branch-cuts: + +Branch Cuts +----------- + +In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. + +For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. + +Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. + +In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. + +.. warning:: + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. + + +.. _complex-number-ordering: + +Complex Number Ordering +----------------------- + +Given a set :math:`\{a_1, \ldots, a_n\}`, an order relation must satisfy the following properties: + +1. **Reflexive**: for any :math:`a` in the set, :math:`a \leq a`. +2. **Transitive**: for any :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`b \leq c`, then :math:`a \leq c`. +3. **Antisymmetric**: for any :math:`a` and :math:`b` in the set, if :math:`a \leq b` and :math:`b \leq a`, then :math:`a = b`. +4. **Total Order**: in addition to the *partial order* established by 1-3, for any :math:`a` and :math:`b` in the set, either :math:`a \leq b` or :math:`b \leq a` (or both). +5. **Compatible with Addition**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b`, then :math:`a + c \leq b + c`. +6. **Compatible with Multiplication**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`0 \leq c`, then :math:`ac \leq bc`. + +Defining an order relation for complex numbers which satisfies all six properties defined above is not possible. Accordingly, this specification does not require that a conforming implementation of the array API standard adopt any specific complex number order relation. + +In order to satisfy backward compatibility guarantees, conforming implementations of the array API standard may choose to define an ordering for complex numbers (e.g., lexicographic); however, consumers of the array API standard should **not** assume that complex number ordering is consistent between implementations or even supported. + +If a conforming implementation chooses to define an ordering for complex numbers, the ordering must be clearly documented. + + +Valued-based Promotion +---------------------- + +According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. + +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/2023.12/design_topics/copies_views_and_mutation.rst b/spec/2023.12/design_topics/copies_views_and_mutation.rst new file mode 100644 index 000000000..52be1c805 --- /dev/null +++ b/spec/2023.12/design_topics/copies_views_and_mutation.rst @@ -0,0 +1,77 @@ +.. _copyview-mutability: + +Copy-view behaviour and mutability +================================== + +.. admonition:: Mutating views + :class: important + + Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may be either a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. + +Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically +have the concept of a "view", meaning an array containing data in memory that +belongs to another array (i.e. a different "view" on the original data). +Views are useful for performance reasons - not copying data to a new location +saves memory and is faster than copying - but can also affect the semantics +of code. This happens when views are combined with *mutating* operations. +This simple example illustrates that: + +.. code-block:: python + + x = ones(1) + y = x[:] # `y` *may* be a view on the data of `x` + y -= 1 # if `y` is a view, this modifies `x` + +Code as simple as the above example will not be portable between array +libraries - for NumPy/PyTorch/CuPy/MXNet ``x`` will contain the value ``0``, +while for TensorFlow/JAX/Dask it will contain the value ``1``. The combination +of views and mutability is fundamentally problematic here if the goal is to +be able to write code with unambiguous semantics. + +Views are necessary for getting good performance out of the current strided +array libraries. It is not always clear however when a library will return a +view, and when it will return a copy. This API standard does not attempt to +specify this - libraries can do either. + +There are several types of operations that do in-place mutation of data +contained in arrays. These include: + +1. Inplace operators (e.g. ``*=``) +2. Item assignment (e.g. ``x[0] = 1``) +3. Slice assignment (e.g., ``x[:2, :] = 3``) +4. The `out=` keyword present in some strided array libraries (e.g. ``sin(x, out=y)``) + +Libraries like TensorFlow and JAX tend to support inplace operators, provide +alternative syntax for item and slice assignment (e.g. an ``update_index`` +function or ``x.at[idx].set(y)``), and have no need for ``out=``. + +A potential solution could be to make views read-only, or use copy-on-write +semantics. Both are hard to implement and would present significant issues +for backwards compatibility for current strided array libraries. Read-only +views would also not be a full solution, given that mutating the original +(base) array will also result in ambiguous semantics. Hence this API standard +does not attempt to go down this route. + +Both inplace operators and item/slice assignment can be mapped onto +equivalent functional expressions (e.g. ``x[idx] = val`` maps to +``x.at[idx].set(val)``), and given that both inplace operators and item/slice +assignment are very widely used in both library and end user code, this +standard chooses to include them. + +The situation with ``out=`` is slightly different - it's less heavily used, and +easier to avoid. It's also not an optimal API, because it mixes an +"efficiency of implementation" consideration ("you're allowed to do this +inplace") with the semantics of a function ("the output _must_ be placed into +this array). There are libraries that do some form of tracing or abstract +interpretation over a language that does not support mutation (to make +analysis easier); in those cases implementing ``out=`` with correct handling of +views may even be impossible to do. There's alternatives, for example the +donated arguments in JAX or working buffers in LAPACK, that allow the user to +express "you _may_ overwrite this data, do whatever is fastest". Given that +those alternatives aren't widely used in array libraries today, this API +standard chooses to (a) leave out ``out=``, and (b) not specify another method +of reusing arrays that are no longer needed as buffers. + +This leaves the problem of the initial example - with this API standard it +remains possible to write code that will not work the same for all array +libraries. This is something that the user must be careful about. diff --git a/spec/2023.12/design_topics/data_dependent_output_shapes.rst b/spec/2023.12/design_topics/data_dependent_output_shapes.rst new file mode 100644 index 000000000..43daa9765 --- /dev/null +++ b/spec/2023.12/design_topics/data_dependent_output_shapes.rst @@ -0,0 +1,15 @@ +.. _data-dependent-output-shapes: + +Data-dependent output shapes +============================ + +Array libraries which build computation graphs commonly employ static analysis that relies upon known shapes. For example, JAX requires known array sizes when compiling code, in order to perform static memory allocation. Functions and operations which are value-dependent present difficulties for such libraries, as array sizes cannot be inferred ahead of time without also knowing the contents of the respective arrays. + +While value-dependent functions and operations are not impossible to implement for array libraries which build computation graphs, this specification does not want to impose an undue burden on such libraries and permits omission of value-dependent operations. All other array libraries are expected, however, to implement the value-dependent operations included in this specification in order to be array specification compliant. + +Value-dependent operations are demarcated in this specification using an admonition similar to the following: + +.. admonition:: Data-dependent output shape + :class: important + + The shape of the output array for this function/operation depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function/operation difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. diff --git a/spec/2023.12/design_topics/data_interchange.rst b/spec/2023.12/design_topics/data_interchange.rst new file mode 100644 index 000000000..3b3040672 --- /dev/null +++ b/spec/2023.12/design_topics/data_interchange.rst @@ -0,0 +1,105 @@ +.. _data-interchange: + +Data interchange mechanisms +=========================== + +This section discusses the mechanism to convert one type of array into another. +As discussed in the :ref:`assumptions-dependencies ` section, +*functions* provided by an array library are not expected to operate on +*array types* implemented by another library. Instead, the array can be +converted to a "native" array type. + +The interchange mechanism must offer the following: + +1. Data access via a protocol that describes the memory layout of the array + in an implementation-independent manner. + + *Rationale: any number of libraries must be able to exchange data, and no + particular package must be needed to do so.* + +2. Support for all dtypes in this API standard (see :ref:`data-types`). + +3. Device support. It must be possible to determine on what device the array + that is to be converted lives. + + *Rationale: there are CPU-only, GPU-only, and multi-device array types; + it's best to support these with a single protocol (with separate + per-device protocols it's hard to figure out unambiguous rules for which + protocol gets used, and the situation will get more complex over time + as TPU's and other accelerators become more widely available).* + +4. Zero-copy semantics where possible, making a copy only if needed (e.g. + when data is not contiguous in memory). + + *Rationale: performance.* + +5. A Python-side and a C-side interface, the latter with a stable C ABI. + + *Rationale: all prominent existing array libraries are implemented in + C/C++, and are released independently from each other. Hence a stable C + ABI is required for packages to work well together.* + +DLPack: An in-memory tensor structure +------------------------------------- + +The best candidate for this protocol is +`DLPack `_, and hence that is what this +standard has chosen as the primary/recommended protocol. Note that the +``asarray`` function also supports the Python buffer protocol (CPU-only) to +support libraries that already implement buffer protocol support. + +.. note:: + The main alternatives to DLPack are device-specific methods: + + - The `buffer protocol `_ on CPU + - ``__cuda_array_interface__`` for CUDA, specified in the Numba documentation + `here `_ + (Python-side only at the moment) + + An issue with device-specific protocols are: if two libraries both + support multiple device types, in which order should the protocols be + tried? A growth in the number of protocols to support each time a new + device gets supported by array libraries (e.g. TPUs, AMD GPUs, emerging + hardware accelerators) also seems undesirable. + + In addition to the above argument, it is also clear from adoption + patterns that DLPack has the widest support. The buffer protocol, despite + being a lot older and standardized as part of Python itself via PEP 3118, + hardly has any support from array libraries. CPU interoperability is + mostly dealt with via the NumPy-specific ``__array__`` (which, when called, + means the object it is attached to must return a ``numpy.ndarray`` + containing the data the object holds). + + See the `RFC to adopt DLPack `_ + for discussion that preceded the adoption of DLPack. + +DLPack's documentation can be found at: https://dmlc.github.io/dlpack/latest/. + +The `Python specification of DLPack `__ +page gives a high-level specification for data exchange in Python using DLPack. + +.. note:: + DLPack is a standalone protocol/project and can therefore be used outside of + this standard. Python libraries that want to implement only DLPack support + are recommended to do so using the same syntax and semantics as outlined + below. They are not required to return an array object from ``from_dlpack`` + which conforms to this standard. + +Non-supported use cases +----------------------- + +Use of DLPack requires that the data can be represented by a strided, in-memory +layout on a single device. This covers usage by a large range of, but not all, +known and possible array libraries. Use cases that are not supported by DLPack +include: + +- Distributed arrays, i.e., the data residing on multiple nodes or devices, +- Sparse arrays, i.e., sparse representations where a data value (typically + zero) is implicit. + +There may be other reasons why it is not possible or desirable for an +implementation to materialize the array as strided data in memory. In such +cases, the implementation may raise a `BufferError` in the `__dlpack__` or +`__dlpack_device__` method. In case an implementation is never able to export +its array data via DLPack, it may omit `__dlpack__` and `__dlpack_device__` +completely, and hence `from_dlpack` may raise an `AttributeError`. diff --git a/spec/2023.12/design_topics/device_support.rst b/spec/2023.12/design_topics/device_support.rst new file mode 100644 index 000000000..593b0b9fa --- /dev/null +++ b/spec/2023.12/design_topics/device_support.rst @@ -0,0 +1,112 @@ +.. _device-support: + +Device support +============== + +For libraries that support execution on more than a single hardware device - e.g. CPU and GPU, or multiple GPUs - it is important to be able to control on which device newly created arrays get placed and where execution happens. Attempting to be fully implicit doesn't always scale well to situations with multiple GPUs. + +Existing libraries employ one or more of these three methods to exert such control over data placement: + +1. A global default device, which may be fixed or user-switchable. +2. A context manager to control device assignment within its scope. +3. Local control for data allocation target device via explicit keywords, and a method to transfer arrays to another device. + +Libraries differ in how execution is controlled, via a context manager or with the convention that execution takes place on the same device where all argument arrays are allocated. And they may or may not allow mixing arrays on different devices via implicit data transfers. + +This standard chooses to add support for method 3 (local control), with the convention that execution takes place on the same device where all argument arrays are allocated. The rationale for choosing method 3 is because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see :ref:`device-out-of-scope` for details. + +Intended usage +-------------- + +The intended usage for the device support in the current version of the +standard is *device handling in library code*. The assumed pattern is that +users create arrays (for which they can use all the relevant device syntax +that the library they use provides), and that they then pass those arrays +into library code which may have to do the following: + +- Create new arrays on the same device as an array that's passed in. +- Determine whether two input arrays are present on the same device or not. +- Move an array from one device to another. +- Create output arrays on the same device as the input arrays. +- Pass on a specified device to other library code. + +.. note:: + Given that there is not much that's currently common in terms of + device-related syntax between different array libraries, the syntax included + in the standard is kept as minimal as possible while enabling the + above-listed use cases. + +Syntax for device assignment +---------------------------- + +The array API provides the following syntax for device assignment and +cross-device data transfer: + +1. A ``.device`` property on the array object, which returns a ``Device`` object + representing the device the data in the array is stored on, and supports + comparing devices for equality with ``==`` and ``!=`` within the same library + (e.g., by implementing ``__eq__``); comparing device objects from different + libraries is out of scope). +2. A ``device=None`` keyword for array creation functions, which takes an + instance of a ``Device`` object. +3. A ``.to_device`` method on the array object to copy an array to a different device. + +.. note:: + The current API standard does **not** include a universal ``Device`` object + recognized by all compliant libraries. Accordingly, the standard does not + provide a means of instantiating a ``Device`` object to point to a specific + physical or logical device. + + The choice to not include a standardized ``Device`` object may be revisited + in a future revision of this standard. + + For array libraries which concern themselves with multi-device support, + including CPU and GPU, they are free to expose a library-specific device + object (e.g., for creating an array on a particular device). While a + library-specific device object can be used as input to ``to_device``, beware + that this will mean non-portability as code will be specific to that + library. + +Semantics +--------- + +Handling devices is complex, and some frameworks have elaborate policies for +handling device placement. Therefore this section only gives recommendations, +rather than hard requirements: + +- Respect explicit device assignment (i.e. if the input to the ``device=`` keyword is not ``None``, guarantee that the array is created on the given device, and raise an exception otherwise). +- Preserve device assignment as much as possible (e.g. output arrays from a function are expected to be on the same device as input arrays to the function). +- Raise an exception if an operation involves arrays on different devices (i.e. avoid implicit data transfer between devices). +- Use a default for ``device=None`` which is consistent between functions within the same library. +- If a library has multiple ways of controlling device placement, the most explicit method should have the highest priority. For example: + + 1. If ``device=`` keyword is specified, that always takes precedence + + 2. If ``device=None``, then use the setting from a context manager, if set. + + 3. If no context manager was used, then use the global default device/strategy + +.. _device-out-of-scope: + +Out of scope for device support +------------------------------- + +Individual libraries may offers APIs for one or more of the following topics, +however those are out of scope for this standard: + +- Identifying a specific physical or logical device across libraries +- Setting a default device globally +- Stream/queue control +- Distributed allocation +- Memory pinning +- A context manager for device control + +.. note:: + A context manager for controlling the default device is present in most existing array + libraries (NumPy being the exception). There are concerns with using a + context manager however. A context manager can be tricky to use at a high + level, since it may affect library code below function calls (non-local + effects). See, e.g., `this PyTorch issue `_ + for a discussion on a good context manager API. + + Adding a context manager may be considered in a future version of this API standard. diff --git a/spec/2023.12/design_topics/exceptions.rst b/spec/2023.12/design_topics/exceptions.rst new file mode 100644 index 000000000..570fe56e3 --- /dev/null +++ b/spec/2023.12/design_topics/exceptions.rst @@ -0,0 +1,28 @@ +.. _exceptions: + +Exceptions +========== + +This standard specifies expected syntax and semantics for a set of APIs. When +inputs to an API do not match what is expected, libraries may emit warnings, +raise exceptions, or misbehave in unexpected ways. In general, it is not +possible to foresee or specify all the ways in which unexpected or invalid +inputs are provided. Therefore, this standard does not attempt to specify +exception or warning types to the extent needed in order to do exception +handling in a portable manner. In general, it is expected that array library +implementers follow `the guidance given by the documentation of the Python +language `__, and either use +builtin exception or warning types that are appropriate for the +situation or use custom exceptions or warnings that derive from those builtin +ones. + +In specific cases, it may be useful to provide guidance to array library +authors regarding what an appropriate exception is. That guidance will be +phrased as *should* rather than *must* (typically in a *Raises* section), +because (a) there may be reasons for an implementer to deviate, and (b) more +often than not, existing array library implementation already differ in their +choices, and it may not be worth them breaking backward compatibility in order +to comply with a "must" in this standard. + +In other cases, this standard will only specify that an exception should or +must be raised, but not mention what type of exception that is. diff --git a/spec/2023.12/design_topics/index.rst b/spec/2023.12/design_topics/index.rst new file mode 100644 index 000000000..548eda90c --- /dev/null +++ b/spec/2023.12/design_topics/index.rst @@ -0,0 +1,18 @@ +Design topics & constraints +=========================== + +.. toctree:: + :caption: Design topics & constraints + :maxdepth: 1 + + copies_views_and_mutation + data_dependent_output_shapes + lazy_eager + data_interchange + device_support + static_typing + accuracy + exceptions + complex_numbers + C_API + parallelism diff --git a/spec/2023.12/design_topics/lazy_eager.rst b/spec/2023.12/design_topics/lazy_eager.rst new file mode 100644 index 000000000..63297ac73 --- /dev/null +++ b/spec/2023.12/design_topics/lazy_eager.rst @@ -0,0 +1,43 @@ +.. _lazy-eager: + +Lazy vs. eager execution +======================== + +While the execution model for implementations is out of scope of this standard, +there are a few aspects of lazy (or graph-based) execution as contrasted to +eager execution that may have an impact on the prescribed semantics of +individual APIs, and will therefore show up in the API specification. + +One important difference is data-dependent or value-dependent behavior, as +described in :ref:`data-dependent-output-shapes`. Because such behavior is hard +to implement, implementers may choose to omit such APIs from their library. + +Another difference is when the Python language itself prescribes that a +specific type *must* be returned. For those cases, it is not possible to return +a lazy/delayed kind of object to avoid computing a value. This is the case for +five dunder methods: `__bool__`, `__int__`, `__float__`, `__complex__` and +`__index__`. Each implementation has only two choices when one of these methods +is called: + +1. Compute a value of the required type (a Python scalar of type `bool`, `int`, + `float` or `complex`), or +2. Raise an exception. + +When an implementation is 100% lazy, for example when it serializes a +computation graph, computing the value is not possible and hence such an +implementation has no choice but to raise an exception. For a "mostly lazy" +implementation, it may make sense to trigger execution instead - but it is not +required to, both choices are valid. + +A common code construct where this happens is conditional logic, e.g.:: + + vals = compute_something() + if all(vals): + # The if-statement will make Python call the __bool__ method + # on the result of `all(vals)`. + do_something_else() + +Note that the API does not contain control flow constructs, as of now, that +would allow avoiding the implicit `__bool__` call in the example above. The +only control flow-like function is `where`, but there's no function like `cond` +to replace an `if`-statement. diff --git a/spec/2023.12/design_topics/parallelism.rst b/spec/2023.12/design_topics/parallelism.rst new file mode 100644 index 000000000..f013a9cf9 --- /dev/null +++ b/spec/2023.12/design_topics/parallelism.rst @@ -0,0 +1,24 @@ +Parallelism +=========== + +Parallelism is mostly, but not completely, an execution or runtime concern +rather than an API concern. Execution semantics are out of scope for this API +standard, and hence won't be discussed further here. The API related part +involves how libraries allow users to exercise control over the parallelism +they offer, such as: + +- Via environment variables. This is the method of choice for BLAS libraries and libraries using OpenMP. +- Via a keyword to individual functions or methods. Examples include the ``n_jobs`` keyword used in scikit-learn and the ``workers`` keyword used in SciPy. +- Build-time settings to enable a parallel or distributed backend. +- Via letting the user set chunk sizes. Dask uses this approach. + +When combining multiple libraries, one has to deal with auto-parallelization +semantics and nested parallelism. Two things that could help improve the +coordination of parallelization behavior in a stack of Python libraries are: + +1. A common API pattern for enabling parallelism +2. A common library providing a parallelization layer + +Option (1) may possibly fit in a future version of this array API standard. +`array-api issue 4 `_ contains +more detailed discussion on the topic of parallelism. diff --git a/spec/2023.12/design_topics/static_typing.rst b/spec/2023.12/design_topics/static_typing.rst new file mode 100644 index 000000000..26a1fb901 --- /dev/null +++ b/spec/2023.12/design_topics/static_typing.rst @@ -0,0 +1,50 @@ +Static typing +============= + +Good support for static typing both in array libraries and array-consuming +code is desirable. Therefore the exact type or set of types for each +parameter, keyword and return value is specified for functions and methods - +see :ref:`function-and-method-signatures`. That section specifies arrays +simply as ``array``; what that means is dealt with in this section. + +Introducing type annotations in libraries became more relevant only when +Python 2.7 support was dropped at the start of 2020. As a consequence, using +type annotations with array libraries is largely still a work in progress. +This version of the API standard does not deal with trying to type *array +properties* like shape, dimensionality or dtype, because that's not a solved +problem in individual array libraries yet. + +An ``array`` type annotation can mean either the type of one specific array +object, or some superclass or typing Protocol - as long as it is consistent +with the array object specified in :ref:`array-object`. To illustrate by +example: + +.. code-block:: python + + # `Array` is a particular class in the library + def sin(x: Array, / ...) -> Array: + ... + +and + +.. code-block:: python + + # There's some base class `_BaseArray`, and there may be multiple + # array subclasses inside the library + A = TypeVar('A', bound=_BaseArray) + def sin(x: A, / ...) -> A: + ... + +should both be fine. There may be other variations possible. Also note that +this standard does not require that input and output array types are the same +(they're expected to be defined in the same library though). Given that +array libraries don't have to be aware of other types of arrays defined in +other libraries (see :ref:`assumptions-dependencies`), this should be enough +for a single array library. + +That said, an array-consuming library aiming to support multiple array types +may need more - for example a protocol to enable structural subtyping. This +API standard currently takes the position that it does not provide any +reference implementation or package that can or should be relied on at +runtime, hence no such protocol is defined here. This may be dealt with in a +future version of this standard. diff --git a/spec/2023.12/extensions/fourier_transform_functions.rst b/spec/2023.12/extensions/fourier_transform_functions.rst new file mode 100644 index 000000000..170ae390b --- /dev/null +++ b/spec/2023.12/extensions/fourier_transform_functions.rst @@ -0,0 +1,45 @@ +Fourier transform Functions +=========================== + + Array API specification for Fourier transform functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``fft``. + +If implemented, this ``fft`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'fft'): + >>> # Use `xp.fft` + + +Objects in API +-------------- + +A conforming implementation of this ``fft`` extension must provide and support the following functions. + +.. currentmodule:: array_api.fft + +.. + NOTE: please keep the functions and their inverse together + +.. autosummary:: + :toctree: generated + :template: method.rst + + fft + ifft + fftn + ifftn + rfft + irfft + rfftn + irfftn + hfft + ihfft + fftfreq + rfftfreq + fftshift + ifftshift diff --git a/spec/2023.12/extensions/index.rst b/spec/2023.12/extensions/index.rst new file mode 100644 index 000000000..3b9409954 --- /dev/null +++ b/spec/2023.12/extensions/index.rst @@ -0,0 +1,34 @@ +.. _extensions: + +Extensions +========== + +Extensions are coherent sets of functionality that are commonly implemented +across array libraries. Each array library supporting this standard may, but is +not required to, implement an extension. If an extension is supported, it +must be accessible inside the main array API supporting namespace as a separate +namespace. + +Extension module implementors must aim to provide all functions and other +public objects in an extension. The rationale for this is that downstream usage +can then check whether or not the extension is present (using ``hasattr(xp, +'extension_name')`` should be enough), and can then assume that functions are +implemented. This in turn makes it also easy for array-consuming libraries to +document which array libraries they support - e.g., "all libraries implementing +the array API standard and its linear algebra extension". + +The mechanism through which the extension namespace is made available is up to +the implementer, e.g. via a regular submodule that is imported under the +``linalg`` name, or via a module-level ``__getattr__``. + +The functions in an extension must adhere to the same conventions as those in +the array API standard. See :ref:`api-specification`. + +------------------------------------------------------------------------------ + +.. toctree:: + :caption: Extension modules: + :maxdepth: 1 + + fourier_transform_functions + linear_algebra_functions diff --git a/spec/2023.12/extensions/linear_algebra_functions.rst b/spec/2023.12/extensions/linear_algebra_functions.rst new file mode 100644 index 000000000..6759b2260 --- /dev/null +++ b/spec/2023.12/extensions/linear_algebra_functions.rst @@ -0,0 +1,116 @@ +.. _linear-algebra-extension: + +Linear Algebra Extension +======================== + + Array API specification for linear algebra functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``linalg``. + +If implemented, this ``linalg`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'linalg'): + >>> # Use `xp.linalg` + + +Design Principles +----------------- + +A principal goal of this specification is to standardize commonly implemented interfaces among array libraries. While this specification endeavors to avoid straying too far from common practice, this specification does, with due restraint, seek to address design decisions arising more from historical accident than first principles. This is especially true for linear algebra APIs, which have arisen and evolved organically over time and have often been tied to particular underlying implementations (e.g., to BLAS and LAPACK). + +Accordingly, the standardization process affords the opportunity to reduce interface complexity among linear algebra APIs by inferring and subsequently codifying common design themes, thus allowing more consistent APIs. What follows is the set of design principles governing the APIs which follow: + +1. **Batching**: if an operation is explicitly defined in terms of matrices (i.e., two-dimensional arrays), then the associated interface should support "batching" (i.e., the ability to perform the operation over a "stack" of matrices). Example operations include: + + - ``inv``: computing the multiplicative inverse of a square matrix. + - ``cholesky``: performing Cholesky decomposition. + - ``matmul``: performing matrix multiplication. + +2. **Data types**: if an operation requires decimal operations and :ref:`type-promotion` semantics are undefined (e.g., as is the case for mixed-kind promotions), then the associated interface should be specified as being restricted to floating-point data types. While the specification uses the term "SHOULD" rather than "MUST", a conforming implementation of the array API standard should only ignore the restriction provided overly compelling reasons for doing so. Example operations which should be limited to floating-point data types include: + + - ``inv``: computing the multiplicative inverse. + - ``slogdet``: computing the natural logarithm of the absolute value of the determinant. + - ``norm``: computing the matrix or vector norm. + + Certain operations are solely comprised of multiplications and additions. Accordingly, associated interfaces need not be restricted to floating-point data types. However, careful consideration should be given to overflow, and use of floating-point data types may be more prudent in practice. Example operations include: + + - ``matmul``: performing matrix multiplication. + - ``trace``: computing the sum along the diagonal. + - ``cross``: computing the vector cross product. + + Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: + + - ``matrix_transpose``: computing the transpose. + - ``diagonal``: returning the diagonal. + +3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. + + In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: + + - ``eig``: computing both eigenvalues and eignvectors. + - ``eigvals``: computing only eigenvalues. + +4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. + + Historically, at a time when all array computing happened on CPUs, BLAS and LAPACK underpinned most numerical computing libraries and environments. Naturally, language and library abstractions catered to the parameterization of those libraries, often exposing low-level implementation details verbatim in their higher-level interfaces, even if such choices would be considered poor or ill-advised by today's standards (e.g., NumPy's use of `UPLO` in `eigh`). However, the present day is considerably different. While still important, BLAS and LAPACK no longer hold a monopoly over linear algebra operations, especially given the proliferation of devices and hardware on which such operations must be performed. Accordingly, interfaces must be conservative in the parameterization they support in order to best ensure universality. Such conservatism applies even to performance optimization parameters afforded by certain hardware. + +5. **Orthogonality**: an interface should have clearly defined and delineated functionality which, ideally, has no overlap with the functionality of other interfaces in the specification. Providing multiple interfaces which can all perform the same operation creates unnecessary confusion regarding interface applicability (i.e., which interface is best at which time) and decreases readability of both library and user code. Where overlap is possible, the specification must be parsimonious in the number of interfaces, ensuring that each interface provides a unique and compelling abstraction. Examples of related interfaces which provide distinct levels of abstraction (and generality) include: + + - ``vecdot``: computing the dot product of two vectors. + - ``matmul``: performing matrix multiplication (including between two vectors and thus the dot product). + - ``tensordot``: computing tensor contractions (generalized sum-products). + - ``einsum``: expressing operations in terms of Einstein summation convention, including dot products and tensor contractions. + + The above can be contrasted with, e.g., NumPy, which provides the following interfaces for computing the dot product or related operations: + + - ``dot``: dot product, matrix multiplication, and tensor contraction. + - ``inner``: dot product. + - ``vdot``: dot product with flattening and complex conjugation. + - ``multi_dot``: chained dot product. + - ``tensordot``: tensor contraction. + - ``matmul``: matrix multiplication (dot product for two vectors). + - ``einsum``: Einstein summation convention. + + where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. + +.. currentmodule:: array_api.linalg + +Objects in API +-------------- + +A conforming implementation of this ``linalg`` extension must provide and support the following functions. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cholesky + cross + det + diagonal + eigh + eigvalsh + inv + matmul + matrix_norm + matrix_power + matrix_rank + matrix_transpose + outer + pinv + qr + slogdet + solve + svd + svdvals + tensordot + trace + vecdot + vector_norm diff --git a/spec/2023.12/future_API_evolution.md b/spec/2023.12/future_API_evolution.md new file mode 100644 index 000000000..443f683d5 --- /dev/null +++ b/spec/2023.12/future_API_evolution.md @@ -0,0 +1,60 @@ +(future-API-evolution)= + +# Future API standard evolution + +## Scope extensions + +Proposals for scope extensions in a future version of the API standard will follow +the process documented at https://github.com/data-apis/governance/blob/master/process_document.md + +In summary, proposed new APIs go through several maturity stages, and will only be +accepted in a future version of this API standard once they have reached the "Final" +maturity stage, which means multiple array libraries have compliant implementations +and real-world experience from use of those implementations is available. + + +## Backwards compatibility + +Functions, objects, keywords and specified behavior are added to this API standard +only if those are already present in multiple existing array libraries, and if there is +data that those APIs are used. Therefore it is highly unlikely that future versions +of this standard will make backwards-incompatible changes. + +The aim is for future versions to be 100% backwards compatible with older versions. +Any exceptions must have strong rationales and be clearly documented in the updated +API specification. + + +(api-versioning)= + +## Versioning + +This API standard uses the following versioning scheme: + +- The version is date-based, in the form `yyyy.mm` (e.g., `2020.12`). +- The version shall not include a standard way to do `alpha`/`beta`/`rc` or + `.post`/`.dev` type versions. + _Rationale: that's for Python packages, not for a standard._ +- The version must be made available at runtime via an attribute + `__array_api_version__` by a compliant implementation, in `'yyyy.mm'` format + as a string, in the namespace that implements the API standard. + _Rationale: dunder version strings are the standard way of doing this._ + +No utilities for dealing with version comparisons need to be provided; given +the format simple string comparisons with Python operators (`=-`, `<`, `>=`, +etc.) will be enough. + +```{note} + +Rationale for the `yyyy.mm` versioning scheme choice: +the API will be provided as part of a library, which already has a versioning +scheme (typically PEP 440 compliant and in the form `major.minor.bugfix`), +and a way to access it via `module.__version__`. The API standard version is +completely independent from the package version. Given the standardization +process, it resembles a C/C++ versioning scheme (e.g. `C99`, `C++14`) more +than Python package versioning. +``` + +The frequency of releasing a new version of an API standard will likely be at +regular intervals and on the order of one year, however no assumption on +frequency of new versions appearing must be made. diff --git a/spec/2023.12/index.rst b/spec/2023.12/index.rst new file mode 100644 index 000000000..3e51cc68e --- /dev/null +++ b/spec/2023.12/index.rst @@ -0,0 +1,37 @@ +Python array API standard +========================= + +Contents +-------- + +.. toctree:: + :caption: Context + :maxdepth: 1 + + purpose_and_scope + use_cases + assumptions + +.. toctree:: + :caption: API + :maxdepth: 1 + + design_topics/index + future_API_evolution + API_specification/index + extensions/index + +.. toctree:: + :caption: Methodology and Usage + :maxdepth: 1 + + usage_data + verification_test_suite + benchmark_suite + +.. toctree:: + :caption: Other + :maxdepth: 1 + + changelog + license diff --git a/spec/2023.12/license.rst b/spec/2023.12/license.rst new file mode 100644 index 000000000..06ec75dfc --- /dev/null +++ b/spec/2023.12/license.rst @@ -0,0 +1,9 @@ +License +======= + +All content on this website and the corresponding +`GitHub repository `__ is licensed +under the following license: + + .. include:: ../../LICENSE + :parser: myst_parser.sphinx_ diff --git a/spec/2023.12/purpose_and_scope.md b/spec/2023.12/purpose_and_scope.md new file mode 100644 index 000000000..f375c9512 --- /dev/null +++ b/spec/2023.12/purpose_and_scope.md @@ -0,0 +1,470 @@ +# Purpose and scope + +## Introduction + +Python users have a wealth of choice for libraries and frameworks for +numerical computing, data science, machine learning, and deep learning. New +frameworks pushing forward the state of the art in these fields are appearing +every year. One unintended consequence of all this activity and creativity +has been fragmentation in multidimensional array (a.k.a. tensor) libraries - +which are the fundamental data structure for these fields. Choices include +NumPy, Tensorflow, PyTorch, Dask, JAX, CuPy, MXNet, Xarray, and others. + +The APIs of each of these libraries are largely similar, but with enough +differences that it's quite difficult to write code that works with multiple +(or all) of these libraries. This array API standard aims to address that +issue, by specifying an API for the most common ways arrays are constructed +and used. + +Why not simply pick an existing API and bless that as the standard? In short, +because there are often good reasons for the current inconsistencies between +libraries. The most obvious candidate for that existing API is NumPy. However +NumPy was not designed with non-CPU devices, graph-based libraries, or JIT +compilers in mind. Other libraries often deviate from NumPy for good +(necessary) reasons. Choices made in this API standard are often the same +ones NumPy makes, or close to it, but are different where necessary to make +sure all existing array libraries can adopt this API. + + +### This API standard + +This document aims to standardize functionality that exists in most/all array +libraries and either is commonly used or is needed for +consistency/completeness. Usage is determined via analysis of downstream +libraries, see {ref}`usage-data`. An example of consistency is: there are +functional equivalents for all Python operators (including the rarely used +ones). + +Beyond usage and consistency, there's a set of use cases that inform the API +design to ensure it's fit for a wide range of users and situations - see +{ref}`use-cases`. + +A question that may arise when reading this document is: _"what about +functionality that's not present in this document?_ This: + +- means that there is no guarantee the functionality is present in libraries + adhering to the standard +- does _not_ mean that that functionality is unimportant +- may indicate that that functionality, if present in a particular array + library, is unlikely to be present in all other libraries + +### History + +The first library for numerical and scientific computing in Python was +Numeric, developed in the mid-1990s. In the early 2000s a second, similar +library, Numarray, was created. In 2005 NumPy was written, superceding both +Numeric and Numarray and resolving the fragmentation at that time. For +roughly a decade, NumPy was the only widely used array library. Over the past +~5 years, mainly due to the emergence of new hardware and the rise of deep +learning, many other libraries have appeared, leading to more severe +fragmentation. Concepts and APIs in newer libraries were often inspired by +(or copied from) those in older ones - and then changed or improved upon to +fit new needs and use cases. Individual library authors discussed ideas, +however there was never (before this array API standard) a serious attempt +to coordinate between all libraries to avoid fragmentation and arrive at a +common API standard. + +The idea for this array API standard grew gradually out of many conversations +between maintainers during 2019-2020. It quickly became clear that any +attempt to write a new "reference library" to fix the current fragmentation +was infeasible - unlike in 2005, there are now too many different use cases +and too many stakeholders, and the speed of innovation is too high. In May +2020 an initial group of maintainers was assembled in the [Consortium for +Python Data API Standards](https://data-apis.org/) to start drafting a +specification for an array API that could be adopted by each of the existing +array and tensor libraries. That resulted in this document, describing that +API. + + +(Scope)= + +## Scope (includes out-of-scope / non-goals) + +This section outlines what is in scope and out of scope for this API standard. + +### In scope + +The scope of the array API standard includes: + +- Functionality which needs to be included in an array library for it to adhere + to this standard. +- Names of functions, methods, classes and other objects. +- Function signatures, including type annotations. +- Semantics of functions and methods. I.e. expected outputs including precision + for and dtypes of numerical results. +- Semantics in the presence of `nan`'s, `inf`'s, empty arrays (i.e. arrays + including one or more dimensions of size `0`). +- Casting rules, broadcasting, indexing +- Data interchange. I.e. protocols to convert one type of array into another + type, potentially sharing memory. +- Device support. + +Furthermore, meta-topics included in this standard include: + +- Use cases for the API standard and assumptions made in it +- API standard adoption +- API standard versioning +- Future API standard evolution +- Array library and API standard versioning +- Verification of API standard conformance + +The concrete set of functionality that is in scope for this version of the +standard is shown in this diagram: + +![Scope of array API](../_static/images/scope_of_array_API.png) + + +**Goals** for the API standard include: + +- Make it possible for array-consuming libraries to start using multiple types + of arrays as inputs. +- Enable more sharing and reuse of code built on top of the core functionality + in the API standard. +- For authors of new array libraries, provide a concrete API that can be + adopted as is, rather than each author having to decide what to borrow from + where and where to deviate. +- Make the learning curve for users less steep when they switch from one array + library to another one. + + +### Out of scope + +1. Implementations of the standard are out of scope. + + _Rationale: the standard will consist of a document and an accompanying test + suite with which the conformance of an implementation can be verified. Actual + implementations will live in array libraries; no reference implementation is + planned._ + +2. Execution semantics are out of scope. This includes single-threaded vs. + parallel execution, task scheduling and synchronization, eager vs. delayed + evaluation, performance characteristics of a particular implementation of the + standard, and other such topics. + + _Rationale: execution is the domain of implementations. Attempting to specify + execution behavior in a standard is likely to require much more fine-grained + coordination between developers of implementations, and hence is likely to + become an obstacle to adoption._ + +3. Non-Python API standardization (e.g., Cython or NumPy C APIs) + + _Rationale: this is an important topic for some array-consuming libraries, + but there is no widely shared C/Cython API and hence it doesn't make sense at + this point in time to standardize anything. See + the [C API section](design_topics/C_API.rst) for more details._ + +4. Standardization of these dtypes is out of scope: bfloat16, extended + precision floating point, datetime, string, object and void dtypes. + + _Rationale: these dtypes aren't uniformly supported, and their inclusion at + this point in time could put a significant implementation burden on + libraries. It is expected that some of these dtypes - in particular + `bfloat16` - will be included in a future version of the standard._ + +5. The following topics are out of scope: I/O, polynomials, error handling, + testing routines, building and packaging related functionality, methods of + binding compiled code (e.g., `cffi`, `ctypes`), subclassing of an array + class, masked arrays, and missing data. + + _Rationale: these topics are not core functionality for an array library, + and/or are too tied to implementation details._ + +6. NumPy (generalized) universal functions, i.e. ufuncs and gufuncs. + + _Rationale: these are NumPy-specific concepts, and are mostly just a + particular way of building regular functions with a few extra + methods/properties._ + +7. Behaviour for unexpected/invalid input to functions and methods. + + _Rationale: there are a huge amount of ways in which users can provide + invalid or unspecified input to functionality in the standard. Exception + types or other resulting behaviour cannot be completely covered and would + be hard to make consistent between libraries._ + + +**Non-goals** for the API standard include: + +- Making array libraries identical so they can be merged. + + _Each library will keep having its own particular strength, whether it's + offering functionality beyond what's in the standard, performance advantages + for a given use case, specific hardware or software environment support, or + more._ + +- Implement a backend or runtime switching system to be able to switch from one + array library to another with a single setting or line of code. + + _This may be feasible, however it's assumed that when an array-consuming + library switches from one array type to another, some testing and possibly + code adjustment for performance or other reasons may be needed._ + +- Making it possible to mix multiple array libraries in function calls. + + _Most array libraries do not know about other libraries, and the functions + they implement may try to convert "foreign" input, or raise an exception. + This behaviour is hard to specify; ensuring only a single array type is + used is best left to the end user._ + + +### Implications of in/out of scope + +If something is out of scope and therefore will not be part of (the current +version of) the API standard, that means that there are no guarantees that that +functionality works the same way, or even exists at all, across the set of +array libraries that conform to the standard. It does _not_ imply that this +functionality is less important or should not be used. + + +## Stakeholders + +Arrays are fundamental to scientific computing, data science, and machine +learning and deep learning. Hence there are many stakeholders for an array API +standard. The _direct_ stakeholders of this standard are **authors/maintainers of +Python array libraries**. There are many more types of _indirect_ stakeholders +though, including: + +- maintainers of libraries and other programs which depend on array libraries + (called "array-consuming libraries" in the rest of this document) +- authors of non-Python array libraries +- developers of compilers and runtimes with array-specific functionality +- end users + +Libraries that are being actively considered - in terms of current behaviour and +API surface - during the creation of the first version of this standard +include: + +- [NumPy](https://numpy.org) +- [TensorFlow](https://www.tensorflow.org/) +- [PyTorch](https://pytorch.org/) +- [MXNet](https://numpy.mxnet.io/) +- [JAX](https://github.com/google/jax) +- [Dask](https://dask.org/) +- [CuPy](https://cupy.chainer.org/) + +Other Python array libraries that are currently under active development and +could adopt this API standard include: + +- [xarray](https://xarray.pydata.org/) +- [PyData/Sparse](https://sparse.pydata.org) +- [Weld](https://github.com/weld-project/weld) +- [Bohrium](https://bohrium.readthedocs.io/) +- [Arkouda](https://github.com/mhmerrill/arkouda) +- [Legate](https://research.nvidia.com/publication/2019-11_Legate-NumPy%3A-Accelerated) + +There are a huge amount of array-consuming libraries; some of the most +prominent ones that are being taken into account - in terms of current array +API usage or impact of design decisions on them - include (this list is likely +to grow it over time): + +- [Pandas](https://pandas.pydata.org/) +- [SciPy](https://github.com/scipy/scipy) +- [scikit-learn](https://scikit-learn.org/) +- [Matplotlib](https://matplotlib.org/) +- [scikit-image](https://scikit-image.org/) +- [NetworkX](https://networkx.github.io/) + +Array libraries in other languages, some of which may grow a Python API in the +future or have taken inspiration from NumPy or other array libraries, include: + +- [Xtensor](https://xtensor.readthedocs.io) (C++, cross-language) +- [XND](https://xnd.io/) (C, cross-language) +- [stdlib](https://stdlib.io/) (JavaScript) +- [rust-ndarray](https://github.com/rust-ndarray/ndarray) (Rust) +- [rray](https://github.com/r-lib/rray) (R) +- [ND4J](https://github.com/deeplearning4j/nd4j) (JVM) +- [NumSharp](https://github.com/SciSharp/NumSharp) (C#) + +Compilers, runtimes, and dispatching layers for which this API standard may be +relevant: + +- [Cython](https://cython.org/) +- [Numba](http://numba.pydata.org/) +- [Pythran](https://pythran.readthedocs.io/en/latest/) +- [Transonic](https://transonic.readthedocs.io) +- [ONNX](https://onnx.ai/) +- [Apache TVM](https://tvm.apache.org/) +- [MLIR](https://mlir.llvm.org/) +- [TACO](https://github.com/tensor-compiler/taco) +- [unumpy](https://github.com/Quansight-Labs/unumpy) +- [einops](https://github.com/arogozhnikov/einops) +- [Apache Arrow](https://arrow.apache.org/) + + + +## How to read this document + +For guidance on how to read and understand the type annotations included in this specification, consult the Python [documentation](https://docs.python.org/3/library/typing.html). + + +(how-to-adopt-this-api)= + +## How to adopt this API + +Most (all) existing array libraries will find something in this API standard +that is incompatible with a current implementation, and that they cannot +change due to backwards compatibility concerns. Therefore we expect that each +of those libraries will want to offer a standard-compliant API in a _new +namespace_. The question then becomes: how does a user access this namespace? + +The simplest method is: document the import to use to directly access the +namespace (e.g. `import package_name.array_api`). This has two issues though: + +1. Array-consuming libraries that want to support multiple array libraries + then have to explicitly import each library. +2. It is difficult to _version_ the array API standard implementation (see + {ref}`api-versioning`). + +To address both issues, a uniform way must be provided by a conforming +implementation to access the API namespace, namely a [method on the array +object](array.__array_namespace__): + +``` +xp = x.__array_namespace__() +``` + +The method must take one keyword, `api_version=None`, to make it possible to +request a specific API version: + +``` +xp = x.__array_namespace__(api_version='2020.10') +``` + +The `xp` namespace must contain all functionality specified in +{ref}`api-specification`. The namespace may contain other functionality; however, +including additional functionality is not recommended as doing so may hinder +portability and inter-operation of array libraries within user code. + +### Checking an array object for Compliance + +Array-consuming libraries are likely to want a mechanism for determining +whether a provided array is specification compliant. The recommended approach +to check for compliance is by checking whether an array object has an +`__array_namespace__` attribute, as this is the one distinguishing feature of +an array-compliant object. + +Checking for an `__array_namespace__` attribute can be implemented as a small +utility function similar to the following. + +```python +def is_array_api_obj(x): + return hasattr(x, '__array_namespace__') +``` + +```{note} +Providing a "reference library" on which people depend is out-of-scope for +the standard. Hence the standard cannot, e.g., provide an array ABC from +which libraries can inherit to enable an `isinstance` check. However, note +that the `numpy.array_api` implementation aims to provide a reference +implementation with only the behavior specified in this standard - it may +prove useful for verifying one is writing portable code. +``` + +### Discoverability of conforming implementations + +It may be useful to have a way to discover all packages in a Python +environment which provide a conforming array API implementation, and the +namespace that that implementation resides in. +To assist array-consuming libraries which need to create arrays originating +from multiple conforming array implementations, or developers who want to perform +for example cross-library testing, libraries may provide an +{pypa}`entry point ` in order to make an array API +namespace discoverable. + +:::{admonition} Optional feature +Given that entry points typically require build system & package installer +specific implementation, this standard chooses to recommend rather than +mandate providing an entry point. +::: + +The following code is an example for how one can discover installed +conforming libraries: + +```python +from importlib.metadata import entry_points + +try: + eps = entry_points()['array_api'] + ep = next(ep for ep in eps if ep.name == 'package_name') +except TypeError: + # The dict interface for entry_points() is deprecated in py3.10, + # supplanted by a new select interface. + ep = entry_points(group='array_api', name='package_name') + +xp = ep.load() +``` + +An entry point must have the following properties: + +- **group**: equal to `array_api`. +- **name**: equal to the package name. +- **object reference**: equal to the array API namespace import path. + + +* * * + +## Conformance + +A conforming implementation of the array API standard must provide and support +all the functions, arguments, data types, syntax, and semantics described in +this specification. + +A conforming implementation of the array API standard may provide additional +values, objects, properties, data types, and functions beyond those described +in this specification. + +Libraries which aim to provide a conforming implementation but haven't yet +completed such an implementation may, and are encouraged to, provide details on +the level of (non-)conformance. For details on how to do this, see +[Verification - measuring conformance](verification_test_suite.md). + + +* * * + +## Terms and Definitions + +For the purposes of this specification, the following terms and definitions apply. + + + +**array**: +a (usually fixed-size) multidimensional container of items of the same type and size. + +**axis**: +an array dimension. + +**branch cut**: +a curve in the complex plane across which a given complex function fails to be continuous. + +**broadcast**: +automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +**compatible**: +two arrays whose dimensions are compatible (i.e., where the size of each dimension in one array is either equal to one or to the size of the corresponding dimension in a second array). + +**element-wise**: +an operation performed element-by-element, in which individual array elements are considered in isolation and independently of other elements within the same array. + +**matrix**: +a two-dimensional array. + +**rank**: +number of array dimensions (not to be confused with the number of linearly independent columns of a matrix). + +**shape**: +a tuple of `N` non-negative integers that specify the sizes of each dimension and where `N` corresponds to the number of dimensions. + +**singleton dimension**: +a dimension whose size is one. + +**vector**: +a one-dimensional array. + +* * * + +## Normative References + +The following referenced documents are indispensable for the application of this specification. + +- __IEEE 754-2019: IEEE Standard for Floating-Point Arithmetic.__ Institute of Electrical and Electronic Engineers, New York (2019). +- Scott Bradner. 1997. "Key words for use in RFCs to Indicate Requirement Levels". RFC 2119. doi:[10.17487/rfc2119](https://tools.ietf.org/html/rfc2119). diff --git a/spec/2023.12/usage_data.md b/spec/2023.12/usage_data.md new file mode 100644 index 000000000..c2dcd5d65 --- /dev/null +++ b/spec/2023.12/usage_data.md @@ -0,0 +1,86 @@ +(usage-data)= + +# Usage Data + +> Summary of existing array API design and usage. + +## Introduction + +With rare exception, technical standardization ("standardization") occurs neither in a vacuum nor from first principles. Instead, standardization finds its origins in two or more, sometimes competing, implementations differing in design and behavior. These differences introduce friction as those (e.g., downstream end-users and library authors) who operate at higher levels of abstraction must either focus on an implementation subset (e.g., only NumPy-like array libraries) or accommodate variation through increased complexity (e.g., if NumPy array, call method `.foo()`; else if Dask array, call method `.bar()`). + +Standardization aspires to reduce this friction and is a process which codifies that which is common, while still encouraging experimentation and innovation. Through the process of standardization, implementations can align around a subset of established practices and channel development resources toward that which is new and novel. In short, standardization aims to thwart reinventing the proverbial wheel. + +A foundational step in standardization is articulating a subset of established practices and defining those practices in unambiguous terms. To this end, the standardization process must approach the problem from two directions: **design** and **usage**. The former direction seeks to understand + +- current implementation design (APIs, names, signatures, classes, and objects) +- current implementation semantics (calling conventions and behavior) + +while the latter direction seeks to quantify API + +- consumers (e.g., which downstream libraries utilize an API?) +- usage frequency (e.g., how often is an API consumed?) +- consumption patterns (e.g., which optional arguments are provided and in what context?) + +By analyzing both design and usage, the standardization process grounds specification decisions in empirical data and analysis. + +## Design + +To understand API design, standardization follows the following process. + +- Identify a representative sample of commonly used Python array libraries (e.g., NumPy, Dask Array, CuPy, MXNet, JAX, TensorFlow, and PyTorch). +- Acquire public APIs (e.g., by analyzing module exports and scraping public documentation). +- Unify and standardize public API data representation for subsequent analysis. +- Extract commonalities and differences by analyzing the intersection and complement of available APIs. +- Derive a common API subset suitable for standardization (based on prevalence and ease of implementation), where such a subset may include attribute names, method names, and positional and keyword arguments. +- Leverage usage data to validate API need and to inform naming conventions, supported data types, and/or optional arguments. +- Summarize findings and provide tooling for additional analysis and exploration. + +See the [`array-api-comparison`](https://github.com/data-apis/array-api-comparison) +repository for design data and summary analysis. + +## Usage + +To understand usage patterns, standardization follows the following process. + +- Identify a representative sample of commonly used Python libraries ("downstream libraries") which consume the subset of array libraries identified during design analysis (e.g., pandas, Matplotlib, SciPy, Xarray, scikit-learn, and scikit-image). +- Instrument downstream libraries in order to record Python array API calls. +- Collect traces while running downstream library test suites. +- Transform trace data into structured data (e.g., as JSON) for subsequent analysis. +- Generate empirical APIs based on provided arguments and associated types, noting which downstream library called which empirical API and at what frequency. +- Derive a single inferred API which unifies the individual empirical API calling semantics. +- Organize API results in human-readable form as type definition files. +- Compare the inferred API to the documented API. + +The following is an inferred API for `numpy.arange`. The docstring includes the number of lines of code that invoked this function for each downstream library when running downstream library test suites. + +```python +def arange( + _0: object, + /, + *_args: object, + dtype: Union[type, str, numpy.dtype, None] = ..., + step: Union[int, float] = ..., + stop: int = ..., +): + """ + usage.dask: 347 + usage.matplotlib: 359 + usage.pandas: 894 + usage.sample-usage: 4 + usage.scipy: 1173 + usage.skimage: 174 + usage.sklearn: 373 + usage.xarray: 666 + """ + ... +``` + +See the [`python-record-api`](https://github.com/data-apis/python-record-api) repository for source code, usage data, and analysis. To perform a similar analysis on additional downstream libraries, including those not publicly released, see the published PyPI [package](https://pypi.org/project/record_api/). + +## Use in Decision-Making + +Design and usage data support specification decision-making in the following ways. + +- Validate user stories to ensure that proposals satisfy existing needs. +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2023.12/use_cases.md b/spec/2023.12/use_cases.md new file mode 100644 index 000000000..e24aa50db --- /dev/null +++ b/spec/2023.12/use_cases.md @@ -0,0 +1,235 @@ +(use-cases)= + +# Use cases + +Use cases inform the requirements for, and design choices made in, this array +API standard. This section first discusses what types of use cases are +considered, and then works out a few concrete use cases in more detail. + +## Types of use cases + +- Packages that depend on a specific array library currently, and would like + to support multiple of them (e.g. for GPU or distributed array support, for + improved performance, or for reaching a wider user base). +- Writing new libraries/tools that wrap multiple array libraries. +- Projects that implement new types of arrays with, e.g., hardware-specific + optimizations or auto-parallelization behavior, and need an API to put on + top that is familiar to end users. +- End users that want to switch from one library to another without learning + about all the small differences between those libraries. + + +## Concrete use cases + +- {ref}`use-case-scipy` +- {ref}`use-case-einops` +- {ref}`use-case-xtensor` +- {ref}`use-case-numba` + + +(use-case-scipy)= + +### Use case 1: add hardware accelerator and distributed support to SciPy + +When surveying a representative set of advanced users and research software +engineers in 2019 (for [this NSF proposal](https://figshare.com/articles/Mid-Scale_Research_Infrastructure_-_The_Scientific_Python_Ecosystem/8009441)), +the single most common pain point brought up about SciPy was performance. + +SciPy heavily relies on NumPy (its only non-optional runtime dependency). +NumPy provides an array implementation that's in-memory, CPU-only and +single-threaded. Common performance-related wishes users have are: + +- parallel algorithms (can be multi-threaded or multiprocessing based) +- support for distributed arrays (with Dask in particular) +- support for GPUs and other hardware accelerators (shortened to just "GPU" + in the rest of this use case) + +Some parallelism can be supported in SciPy, it has a `workers` keyword +(similar to scikit-learn's `n_jobs` keyword) that allows specifying to use +parallelism in some algorithms. However SciPy itself will not directly start +depending on a GPU or distributed array implementation, or contain (e.g.) +CUDA code - that's not maintainable given the resources for development. +_However_, there is a way to provide distributed or GPU support. Part of the +solution is provided by NumPy's "array protocols" (see [gh-1](https://github.com/data-apis/array-api/issues/1)), that allow +dispatching to other array implementations. The main problem then becomes how +to know whether this will work with a particular distributed or GPU array +implementation - given that there are zero other array implementations that +are even close to providing full NumPy compatibility - without adding that +array implementation as a dependency. + +It's clear that SciPy functionality that relies on compiled extensions (C, +C++, Cython, Fortran) directly can't easily be run on another array library +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python +code can work though. There's two main possibilities: + +1. Testing with another package, manually or in CI, and simply provide a list + of functionality that is found to work. Then make ad-hoc fixes to expand + the set that works. +2. Start relying on a well-defined subset of the NumPy API (or a new + NumPy-like API), for which compatibility is guaranteed. + +Option (2) seems strongly preferable, and that "well-defined subset" is _what +an API standard should provide_. Testing will still be needed, to ensure there +are no critical corner cases or bugs between array implementations, however +that's then a very tractable task. + +As a concrete example, consider the spectral analysis functions in `scipy.signal`. +All of those functions (e.g., `periodogram`, `spectrogram`, `csd`, `welch`, `stft`, +`istft`) are pure Python - with the exception of `lombscargle` which is ~40 +lines of Cython - and uses NumPy function calls, array attributes and +indexing. The beginning of each function could be changed to retrieve the +module that implements the array API standard for the given input array type, +and then functions from that module could be used instead of NumPy functions. + +If the user has another array type, say a CuPy or PyTorch array `x` on their +GPU, doing: +``` +from scipy import signal + +signal.welch(x) +``` +will result in: +``` +# For CuPy +ValueError: object __array__ method not producing an array + +# For PyTorch +TypeError: can't convert cuda:0 device type tensor to numpy. +``` +and therefore the user will have to explicitly convert to and from a +`numpy.ndarray` (which is quite inefficient): +``` +# For CuPy +x_np = cupy.asnumpy(x) +freq, Pxx = (cupy.asarray(res) for res in signal.welch(x_np)) + +# For PyTorch +x_np = x.cpu().numpy() +# Note: ends up with tensors on CPU, may still have to move them back +freq, Pxx = (torch.tensor(res) for res in signal.welch(x_np)) +``` +This code will look a little different for each array library. The end goal +here is to be able to write this instead as: +``` +freq, Pxx = signal.welch(x) +``` +and have `freq`, `Pxx` be arrays of the same type and on the same device as `x`. + +```{note} + +This type of use case applies to many other libraries, from scikit-learn +and scikit-image to domain-specific libraries like AstroPy and +scikit-bio, to code written for a single purpose or user. +``` + +(use-case-einops)= + +### Use case 2: simplify einops by removing the backend system + +[einops](https://github.com/arogozhnikov/einops) is a library that provides flexible tensor operations and supports many array libraries (NumPy, TensorFlow, PyTorch, CuPy, MXNet, JAX). +Most of the code in `einops` is: + +- [einops.py](https://github.com/arogozhnikov/einops/blob/master/einops/einops.py) + contains the functions it offers as public API (`rearrange`, `reduce`, `repeat`). +- [_backends.py](https://github.com/arogozhnikov/einops/blob/master/einops/_backends.py) + contains the glue code needed to support that many array libraries. + +The amount of code in each of those two files is almost the same (~550 LoC each). +The typical pattern in `einops.py` is: +``` +def some_func(x): + ... + backend = get_backend(x) + shape = backend.shape(x) + result = backend.reduce(x) + ... +``` +With a standard array API, the `_backends.py` glue layer could almost completely disappear, +because the purpose it serves (providing a unified interface to array operations from each +of the supported backends) is already addressed by the array API standard. +Hence the complete `einops` code base could be close to 50% smaller, and easier to maintain or add to. + +```{note} + +Other libraries that have a similar backend system to support many array libraries +include [TensorLy](https://github.com/tensorly/tensorly), the (now discontinued) +multi-backend version of [Keras](https://github.com/keras-team/keras), +[Unumpy](https://github.com/Quansight-Labs/unumpy) and +[EagerPy](https://github.com/jonasrauber/eagerpy). Many end users and +organizations will also have such glue code - it tends to be needed whenever +one tries to support multiple array types in a single API. +``` + + +(use-case-xtensor)= + +### Use case 3: adding a Python API to xtensor + +[xtensor](https://github.com/xtensor-stack/xtensor) is a C++ array library +that is NumPy-inspired and provides lazy arrays. It has Python (and Julia and R) +bindings, however it does not have a Python array API. + +Xtensor aims to follow NumPy closely, however it only implements a subset of functionality +and documents some API differences in +[Notable differences with NumPy](https://xtensor.readthedocs.io/en/latest/numpy-differences.html). + +Note that other libraries document similar differences, see for example +[this page for JAX](https://jax.readthedocs.io/en/latest/jax.numpy.html) and +[this page for TensorFlow](https://www.tensorflow.org/guide/tf_numpy). + +Each time an array library author designs a new API, they have to choose (a) +what subset of NumPy makes sense to implement, and (b) where to deviate +because NumPy's API for a particular function is suboptimal or the semantics +don't fit their execution model. + +This array API standard aims to provide an API that can be readily adopted, +without having to make the above-mentioned choices. + +```{note} + +XND is another array library, written in C, that still needs a Python API. +Array implementations in other languages are often in a similar situation, +and could translate this array API standard 1:1 to their language. +``` + + +(use-case-numba)= + +### Use case 4: make JIT compilation of array computations easier and more robust + +[Numba](https://github.com/numba/numba) is a Just-In-Time (JIT) compiler for +numerical functions in Python; it is NumPy-aware. [PyPy](https://pypy.org) +is an implementation of Python with a JIT at its core; its NumPy support relies +on running NumPy itself through a compatibility layer (`cpyext`), while a +previous attempt to implement NumPy support directly was unsuccessful. + +Other array libraries may have an internal JIT (e.g., TensorFlow, PyTorch, +JAX, MXNet) or work with an external JIT like +[XLA](https://www.tensorflow.org/xla) or [VTA](https://tvm.apache.org/docs/vta/index.html). + +Numba currently has to jump through some hoops to accommodate NumPy's casting rules +and may not attain full compatibility with NumPy in some cases - see, e.g., +[this](https://github.com/numba/numba/issues/4749) or +[this](https://github.com/numba/numba/issues/5907) example issue regarding (array) scalar +return values. + +An [explicit suggestion from a Numba developer](https://twitter.com/esc___/status/1295389487485333505) +for this array API standard was: + +> for JIT compilers (e.g. Numba) it will be important, that the type of the + returned value(s) depends only on the *types* of the input but not on the + *values*. + +A concrete goal for this use case is to have better matching between +JIT-compiled and non-JIT execution. Here is an example from the Numba code +base, the need for which should be avoided in the future: + +``` +def check(x, y): + got = cfunc(x, y) + np.testing.assert_array_almost_equal(got, pyfunc(x, y)) + # Check the power operation conserved the input's dtype + # (this is different from Numpy, whose behaviour depends on + # the *values* of the arguments -- see PyArray_CanCastArrayTo). + self.assertEqual(got.dtype, x.dtype) +``` diff --git a/spec/2023.12/verification_test_suite.md b/spec/2023.12/verification_test_suite.md new file mode 100644 index 000000000..cbe770e48 --- /dev/null +++ b/spec/2023.12/verification_test_suite.md @@ -0,0 +1,62 @@ +# Verification - test suite + +## Measuring conformance + +In addition to the specification documents, a test suite is being developed to +aid library developers check conformance to the spec. **NOTE: The test suite +is still a work in progress.** It can be found at +. + +It is important to note that while the aim of the array API test suite is to +cover as much of the spec as possible, there are necessarily some aspects of +the spec that are not covered by the test suite, typically because they are +impossible to effectively test. Furthermore, if the test suite appears to +diverge in any way from what the spec documents say, this should be considered +a bug in the test suite. The specification is the ground source of truth. + +## Running the tests + +To run the tests, first clone the [test suite +repo](https://github.com/data-apis/array-api-tests), and install the testing +dependencies, + + pip install pytest hypothesis + +or + + conda install pytest hypothesis + +as well as the array libraries that you want to test. To run the tests, you +need to specify the array library that is to be tested. There are two ways to +do this. One way is to set the `ARRAY_API_TESTS_MODULE` environment variable. +For example + + ARRAY_API_TESTS_MODULE=numpy pytest + +Alternatively, edit the `array_api_tests/_array_module.py` file and change the +line + +```py +array_module = None +``` + +to + +```py +import numpy as array_module +``` + +(replacing `numpy` with the array module namespace to be tested). + +In either case, the tests should be run with the `pytest` command. + +Aside from the two testing dependencies (`pytest` and `hypothesis`), the test +suite has no dependencies. In particular, it does not depend on any specific +array libraries such as NumPy. All tests are run using only the array library +that is being tested, comparing results against the behavior as defined in the +spec. The test suite is designed to be standalone so that it can easily be vendored. + +See the +[README](https://github.com/data-apis/array-api-tests/blob/master/README.md) +in the test suite repo for more information about how to run and interpret the +test suite results. diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json index ad38507bb..04777bd78 100644 --- a/spec/_ghpages/versions.json +++ b/spec/_ghpages/versions.json @@ -1,6 +1,7 @@ { "2021.12": "2021.12", "2022.12": "2022.12", + "2023.12": "2023.12", "latest": "latest", "draft": "draft" } diff --git a/src/.DS_Store b/src/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..dd19daea5d1a7b84e37b40dd1eb49bfc451dd50b GIT binary patch literal 6148 zcmeHKOG-mQ5UkcL0xrzbzd)!;&mE;Ee}t(zyiRW?uaiBQ}gHU6T7I45$QbR6ZhEQ9WTW5%(>U(?D*S^_)rPCZTp zSWi@x0#abCz-4Y1-v96DC+7b#NjoVZ1^$%+He0P%OTJR|*2&9xuWj@Py4QTu-M9`4 nL$qUJv}10(9p6Mz)-_-Ac`qCigU)==iTX3(y2zx!Un}qfHa!=x literal 0 HcmV?d00001 diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 9233df3c4..ec5d56d58 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- project = "Python array API standard" -copyright = "2020-2022, Consortium for Python Data API Standards" +copyright = "2020-2024, Consortium for Python Data API Standards" author = "Consortium for Python Data API Standards" # -- General configuration --------------------------------------------------- diff --git a/src/array_api_stubs/_2023_12/__init__.py b/src/array_api_stubs/_2023_12/__init__.py new file mode 100644 index 000000000..8415f2765 --- /dev/null +++ b/src/array_api_stubs/_2023_12/__init__.py @@ -0,0 +1,25 @@ +"""Function stubs and API documentation for the array API standard.""" + +from .array_object import * +from .constants import * +from .creation_functions import * +from .data_type_functions import * +from . import 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 .set_functions import * +from .sorting_functions import * +from .statistical_functions import * +from .utility_functions import * +from . import linalg +from . import fft +from . import info + + +__array_api_version__: str = "YYYY.MM" +""" +String representing the version of the array API specification which the conforming implementation adheres to. +""" diff --git a/src/array_api_stubs/_2023_12/_types.py b/src/array_api_stubs/_2023_12/_types.py new file mode 100644 index 000000000..7c3d903d7 --- /dev/null +++ b/src/array_api_stubs/_2023_12/_types.py @@ -0,0 +1,144 @@ +""" +Types for type annotations used in the array API standard. + +The type variables should be replaced with the actual types for a given +library, e.g., for NumPy TypeVar('array') would be replaced with ndarray. +""" +from __future__ import annotations + +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", + "DefaultDataTypes", + "DataTypes", + "Capabilities", + "Info", +] + +from dataclasses import dataclass +from typing import ( + Any, + List, + Literal, + Optional, + Sequence, + Tuple, + TypedDict, + TypeVar, + Union, + Protocol, +) +from enum import Enum + +array = TypeVar("array") +device = TypeVar("device") +dtype = TypeVar("dtype") +SupportsDLPack = TypeVar("SupportsDLPack") +SupportsBufferProtocol = TypeVar("SupportsBufferProtocol") +PyCapsule = TypeVar("PyCapsule") +# ellipsis cannot actually be imported from anywhere, so include a dummy here +# to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 +ellipsis = TypeVar("ellipsis") + + +@dataclass +class finfo_object: + """Dataclass returned by `finfo`.""" + + bits: int + eps: float + max: float + min: float + smallest_normal: float + dtype: dtype + + +@dataclass +class iinfo_object: + """Dataclass returned by `iinfo`.""" + + bits: int + max: int + min: int + dtype: dtype + + +_T_co = TypeVar("_T_co", covariant=True) + + +class NestedSequence(Protocol[_T_co]): + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: + ... + + def __len__(self, /) -> int: + ... + + +class Info(Protocol): + """Namespace returned by `__array_namespace_info__`.""" + + def capabilities(self) -> Capabilities: + ... + + def default_device(self) -> device: + ... + + def default_dtypes(self, *, device: Optional[device]) -> DefaultDataTypes: + ... + + def devices(self) -> List[device]: + ... + + def dtypes( + self, *, device: Optional[device], kind: Optional[Union[str, Tuple[str, ...]]] + ) -> DataTypes: + ... + + +DefaultDataTypes = TypedDict( + "DefaultDataTypes", + { + "real floating": dtype, + "complex floating": dtype, + "integral": dtype, + "indexing": dtype, + }, +) +DataTypes = TypedDict( + "DataTypes", + { + "bool": dtype, + "float32": dtype, + "float64": dtype, + "complex64": dtype, + "complex128": dtype, + "int8": dtype, + "int16": dtype, + "int32": dtype, + "int64": dtype, + "uint8": dtype, + "uint16": dtype, + "uint32": dtype, + "uint64": dtype, + }, + total=False, +) +Capabilities = TypedDict( + "Capabilities", {"boolean indexing": bool, "data-dependent shapes": bool} +) diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py new file mode 100644 index 000000000..6dd70c278 --- /dev/null +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -0,0 +1,1219 @@ +from __future__ import annotations + +__all__ = ["array"] + +from ._types import ( + array, + dtype as Dtype, + device as Device, + Optional, + Tuple, + Union, + Any, + PyCapsule, + Enum, + ellipsis, +) + + +class _array: + def __init__(self: array) -> None: + """Initialize the attributes for the array object class.""" + + @property + def dtype(self: array) -> Dtype: + """ + Data type of the array elements. + + Returns + ------- + out: dtype + array data type. + """ + + @property + def device(self: array) -> Device: + """ + Hardware device the array data resides on. + + Returns + ------- + out: device + a ``device`` object (see :ref:`device-support`). + """ + + @property + def mT(self: array) -> array: + """ + Transpose of a matrix (or a stack of matrices). + + If an array instance has fewer than two dimensions, an error should be raised. + + Returns + ------- + out: array + array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape ``(..., M, N)``, the returned array must have shape ``(..., N, M)``). The returned array must have the same data type as the original array. + """ + + @property + def ndim(self: array) -> int: + """ + Number of array dimensions (axes). + + Returns + ------- + out: int + number of array dimensions (axes). + """ + + @property + def shape(self: array) -> Tuple[Optional[int], ...]: + """ + Array dimensions. + + Returns + ------- + out: Tuple[Optional[int], ...] + array dimensions. An array dimension must be ``None`` if and only if a dimension is unknown. + + + .. note:: + For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; ``A[:, B > 0]``) and thus cannot be statically resolved without knowing array contents. + + .. note:: + The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. + """ + + @property + def size(self: array) -> Optional[int]: + """ + Number of elements in an array. + + .. note:: + This must equal the product of the array's dimensions. + + Returns + ------- + out: Optional[int] + number of elements in an array. The returned value must be ``None`` if and only if one or more array dimensions are unknown. + + + .. note:: + For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. + """ + + @property + def T(self: array) -> array: + """ + Transpose of the array. + + The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. + + Returns + ------- + out: array + two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. + + + .. note:: + Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional ``permute_dims`` interface found in this specification. + """ + + def __abs__(self: array, /) -> array: + """ + Calculates the absolute value for each element of an array instance. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __add__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the sum for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance (augend array). Should have a numeric data type. + other: Union[int, float, array] + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __and__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i & other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. + """ + + def __array_namespace__( + self: array, /, *, api_version: Optional[str] = None + ) -> Any: + """ + Returns an object that has all the array API functions on it. + + Parameters + ---------- + self: array + array instance. + api_version: Optional[str] + string representing the version of the array API specification to be returned, in ``'YYYY.MM'`` form, for example, ``'2020.10'``. If it is ``None``, it should return the namespace corresponding to latest version of the array API specification. If the given version is invalid or not implemented for the given module, an error should be raised. Default: ``None``. + + Returns + ------- + out: Any + an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. + """ + + def __bool__(self: array, /) -> bool: + """ + Converts a zero-dimensional array to a Python ``bool`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: bool + a Python ``bool`` object representing the single element of the array. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``True``. + - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``bool``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __complex__(self: array, /) -> complex: + """ + Converts a zero-dimensional array to a Python ``complex`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: complex + a Python ``complex`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1+0j``. + - If ``self`` is ``False``, the result is ``0+0j``. + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. + - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. + - If ``self`` is a finite number, the result is ``self + 0j``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __dlpack__( + self: array, + /, + *, + stream: Optional[Union[int, Any]] = None, + max_version: Optional[tuple[int, int]] = None, + dl_device: Optional[tuple[Enum, int]] = None, + copy: Optional[bool] = None, + ) -> PyCapsule: + """ + Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. + + Parameters + ---------- + self: array + array instance. + stream: Optional[Union[int, Any]] + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be an integer larger than or equal to ``-1`` (see below for allowed values on each platform). If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. + + For other device types which do have a stream, queue, or similar synchronization/ordering mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + + .. note:: + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + + Device-specific values of ``stream`` for CUDA: + + - ``None``: producer must assume the legacy default stream (default). + - ``1``: the legacy default stream. + - ``2``: the per-thread default stream. + - ``> 2``: stream number represented as a Python integer. + - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. + + Device-specific values of ``stream`` for ROCm: + + - ``None``: producer must assume the legacy default stream (default). + - ``0``: the default stream. + - ``> 2``: stream number represented as a Python integer. + - Using ``1`` and ``2`` is not supported. + + .. note:: + When ``dl_device`` is provided explicitly, ``stream`` must be a valid + construct for the specified device type. In particular, when ``kDLCPU`` + is in use, ``stream`` must be ``None`` and a synchronization must be + performed to ensure data safety. + + .. admonition:: Tip + :class: important + + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronizations than necessary. + max_version: Optional[tuple[int, int]] + the maximum DLPack version that the *consumer* (i.e., the caller of + ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. + This method may return a capsule of version ``max_version`` (recommended + if it does support that), or of a different version. + This means the consumer must verify the version even when + `max_version` is passed. + dl_device: Optional[tuple[enum.Enum, int]] + the DLPack device type. Default is ``None``, meaning the exported capsule + should be on the same device as ``self`` is. When specified, the format + must be a 2-tuple, following that of the return value of :meth:`array.__dlpack_device__`. + If the device type cannot be handled by the producer, this function must + raise ``BufferError``. + + The v2023.12 standard only mandates that a compliant library should offer a way for + ``__dlpack__`` to return a capsule referencing an array whose underlying memory is + accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). + If a copy must be made to enable this support but ``copy`` is set to ``False``, the + function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this + API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the + function must always copy (performed by the producer). If ``False``, the + function must never copy, and raise a ``BufferError`` in case a copy is + deemed necessary (e.g. if a cross-device data movement is requested, and + it is not possible without a copy). If ``None``, the function must reuse + the existing memory buffer if possible and copy otherwise. Default: ``None``. + + When a copy happens, the ``DLPACK_FLAG_BITMASK_IS_COPIED`` flag must be set. + + .. note:: + If a copy happens, and if the consumer-provided ``stream`` and ``dl_device`` + can be understood by the producer, the copy must be performed over ``stream``. + + Returns + ------- + capsule: PyCapsule + a DLPack capsule for the array. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + Implementations should raise ``BufferError`` when the data cannot + be exported as DLPack (e.g., incompatible dtype or strides). Other + errors are raised when export fails for other reasons (e.g., incorrect + arguments passed or out of memory). + + Notes + ----- + The DLPack version scheme is SemVer, where the major DLPack versions + represent ABI breaks, and minor versions represent ABI-compatible additions + (e.g., new enum values for new data types or device types). + + The ``max_version`` keyword was introduced in v2023.12, and goes + together with the ``DLManagedTensorVersioned`` struct added in DLPack + 1.0. This keyword may not be used by consumers until a later time after + introduction, because producers may implement the support at a different + point in time. + + It is recommended for the producer to use this logic in the implementation + of ``__dlpack__``: + + .. code:: python + + if max_version is None: + # Keep and use the DLPack 0.X implementation + # Note: from March 2025 onwards (but ideally as late as + # possible), it's okay to raise BufferError here + else: + # We get to produce `DLManagedTensorVersioned` now. Note that + # our_own_dlpack_version is the max version that the *producer* + # supports and fills in the `DLManagedTensorVersioned::version` + # field + if max_version >= our_own_dlpack_version: + # Consumer understands us, just return a Capsule with our max version + elif max_version[0] == our_own_dlpack_version[0]: + # major versions match, we should still be fine here - + # return our own max version + else: + # if we're at a higher major version internally, did we + # keep an implementation of the older major version around? + # For example, if the producer is on DLPack 1.x and the consumer + # is 0.y, can the producer still export a capsule containing + # DLManagedTensor and not DLManagedTensorVersioned? + # If so, use that. Else, the producer should raise a BufferError + # here to tell users that the consumer's max_version is too + # old to allow the data exchange to happen. + + And this logic for the consumer in :func:`~array_api.from_dlpack`: + + .. code:: python + + try: + x.__dlpack__(max_version=(1, 0), ...) + # if it succeeds, store info from the capsule named "dltensor_versioned", + # and need to set the name to "used_dltensor_versioned" when we're done + except TypeError: + x.__dlpack__(...) + + This logic is also applicable to handling of the new ``dl_device`` and ``copy`` + keywords. + + DLPack 1.0 added a flag to indicate that the array is read-only + (``DLPACK_FLAG_BITMASK_READ_ONLY``). A consumer that does not support + read-only arrays should ignore this flag (this is preferred over + raising an exception; the user is then responsible for ensuring the + memory isn't modified). + + .. versionchanged:: 2022.12 + Added BufferError. + + .. versionchanged:: 2023.12 + Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + + .. versionchanged:: 2023.12 + Added recommendation for handling read-only arrays. + """ + + def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: + """ + Returns device type and device ID in DLPack format. Meant for use within :func:`~array_api.from_dlpack`. + + Parameters + ---------- + self: array + array instance. + + Returns + ------- + device: Tuple[Enum, int] + a tuple ``(device_type, device_id)`` in DLPack format. Valid device type enum members are: + + :: + + CPU = 1 + CUDA = 2 + CPU_PINNED = 3 + OPENCL = 4 + VULKAN = 7 + METAL = 8 + VPI = 9 + ROCM = 10 + CUDA_MANAGED = 13 + ONE_API = 14 + """ + + def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + r""" + Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + """ + + def __float__(self: array, /) -> float: + """ + Converts a zero-dimensional array to a Python ``float`` object. + + .. note:: + Casting integer values outside the representable bounds of Python's float type is not specified and is implementation-dependent. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: float + a Python ``float`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``float``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __floordiv__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i // other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. + """ + + def __ge__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + """ + + def __getitem__( + self: array, + key: Union[ + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, None], ...], + array, + ], + /, + ) -> array: + """ + Returns ``self[key]``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] + index key. + + Returns + ------- + out: array + an array containing the accessed value(s). The returned array must have the same data type as ``self``. + """ + + def __gt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + """ + + def __index__(self: array, /) -> int: + """ + Converts a zero-dimensional integer array to a Python ``int`` object. + + .. note:: + This method is called to implement `operator.index() `_. See also `PEP 357 `_. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have an integer data type. If ``self`` has a floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __int__(self: array, /) -> int: + """ + Converts a zero-dimensional array to a Python ``int`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + For floating-point operands, + + - If ``self`` is a finite number, the result is the integer part of ``self``. + - If ``self`` is ``-0``, the result is ``0``. + + **Raises** + + For floating-point operands, + + - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. + - If ``self`` is ``NaN``, raise ``ValueError``. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __invert__(self: array, /) -> array: + """ + Evaluates ``~self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as `self`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_invert`. + """ + + def __le__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + """ + + def __lshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i << other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. + """ + + def __lt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + """ + + def __matmul__(self: array, other: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + other: array + other array. Should have a numeric data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``self`` and ``other`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``self`` is a one-dimensional array having shape ``(K,)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + - The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. + + **Raises** + + - if either ``self`` or ``other`` is a zero-dimensional array. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __mod__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + """ + + def __mul__(self: array, other: Union[int, float, array], /) -> array: + r""" + Calculates the product for each element of an array instance with the respective element of the array ``other``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + """ + Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __neg__(self: array, /) -> array: + """ + Evaluates ``-self_i`` for each element of an array instance. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``self`` has a complex floating-point data type, both the real and imaginary components for each ``self_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __or__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i | other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + """ + + def __pos__(self: array, /) -> array: + """ + Evaluates ``+self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __pow__(self: array, other: Union[int, float, array], /) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. + + .. note:: + If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Parameters + ---------- + self: array + array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + other: Union[int, float, array] + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __rshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i >> other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. + """ + + def __setitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + ], + value: Union[int, float, bool, array], + /, + ) -> None: + """ + Sets ``self[key]`` to ``value``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + index key. + value: Union[int, float, bool, array] + value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). + + + .. note:: + + Setting array values must not affect the data type of ``self``. + + When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + + When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + """ + + def __sub__(self: array, other: Union[int, float, array], /) -> array: + """ + Calculates the difference for each element of an array instance with the respective element of the array ``other``. + + The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). + + Parameters + ---------- + self: array + array instance (minuend array). Should have a numeric data type. + other: Union[int, float, array] + subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __truediv__(self: array, other: Union[int, float, array], /) -> array: + r""" + Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __xor__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i ^ other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. + """ + + def to_device( + self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None + ) -> array: + """ + Copy the array from the device on which it currently resides to the specified ``device``. + + Parameters + ---------- + self: array + array instance. + device: device + a ``device`` object (see :ref:`device-support`). + stream: Optional[Union[int, Any]] + stream object to use during copy. In addition to the types supported in :meth:`array.__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. + + Returns + ------- + out: array + an array with the same data and data type as ``self`` and located on the specified ``device``. + + + Notes + ----- + + - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. + - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. + + .. versionchanged:: 2023.12 + Clarified behavior when a provided ``device`` object corresponds to the device on which an array instance resides. + """ + + +array = _array diff --git a/src/array_api_stubs/_2023_12/constants.py b/src/array_api_stubs/_2023_12/constants.py new file mode 100644 index 000000000..c5735d09f --- /dev/null +++ b/src/array_api_stubs/_2023_12/constants.py @@ -0,0 +1,30 @@ +__all__ = ["e", "inf", "nan", "newaxis", "pi"] + +e = 2.718281828459045 +""" +IEEE 754 floating-point representation of Euler's constant. + +``e = 2.71828182845904523536028747135266249775724709369995...`` +""" + +inf = float("inf") +""" +IEEE 754 floating-point representation of (positive) infinity. +""" + +nan = float("nan") +""" +IEEE 754 floating-point representation of Not a Number (``NaN``). +""" + +newaxis = None +""" +An alias for ``None`` which is useful for indexing arrays. +""" + +pi = 3.141592653589793 +""" +IEEE 754 floating-point representation of the mathematical constant ``π``. + +``pi = 3.1415926535897932384626433...`` +""" diff --git a/src/array_api_stubs/_2023_12/creation_functions.py b/src/array_api_stubs/_2023_12/creation_functions.py new file mode 100644 index 000000000..6de79268e --- /dev/null +++ b/src/array_api_stubs/_2023_12/creation_functions.py @@ -0,0 +1,647 @@ +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] + + +from ._types import ( + List, + NestedSequence, + Optional, + SupportsBufferProtocol, + Tuple, + Union, + array, + device, + dtype, +) + + +def arange( + start: Union[int, float], + /, + stop: Optional[Union[int, float]] = None, + step: Union[int, float] = 1, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. + + Parameters + ---------- + start: Union[int, float] + if ``stop`` is specified, the start of interval (inclusive); otherwise, the end of the interval (exclusive). If ``stop`` is not specified, the default starting value is ``0``. + stop: Optional[Union[int, float]] + the end of the interval. Default: ``None``. + step: Union[int, float] + the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + + .. note:: + This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. + """ + + +def asarray( + obj: Union[ + array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol + ], + /, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + r""" + Convert the input to an array. + + Parameters + ---------- + obj: Union[array, bool, int, float, complex, NestedSequence[bool | int | float | complex], SupportsBufferProtocol] + object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. + + .. admonition:: Tip + :class: important + + An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. + + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then, in order of precedence, + + - if all values are of type ``bool``, the output data type must be ``bool``. + - if all values are of type ``int`` or are a mixture of ``bool`` and ``int``, the output data type must be the default integer data type. + - if one or more values are ``complex`` numbers, the output data type must be the default complex floating-point data type. + - if one or more values are ``float``\s, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`array_api.astype`. + + .. note:: + If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def empty( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns an uninitialized array having a specified `shape`. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing uninitialized data. + """ + + +def empty_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns an uninitialized array with the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and containing uninitialized data. + """ + + +def eye( + n_rows: int, + n_cols: Optional[int] = None, + /, + *, + k: int = 0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + r""" + Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. + + .. note:: + An output array having a complex floating-point data type must have the value ``1 + 0j`` along the ``k``\th diagonal and ``0 + 0j`` elsewhere. + + Parameters + ---------- + n_rows: int + number of rows in the output array. + n_cols: Optional[int] + number of columns in the output array. If ``None``, the default number of columns in the output array is equal to ``n_rows``. Default: ``None``. + k: int + index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and ``0`` to the main diagonal. Default: ``0``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def from_dlpack( + x: object, + /, + *, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + """ + Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. + + Parameters + ---------- + x: object + input (array) object. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``x`` supports DLPack, the output array must be on the same device as ``x``. Default: ``None``. + + The v2023.12 standard only mandates that a compliant library should offer a way for ``from_dlpack`` to return an array + whose underlying memory is accessible to the Python interpreter, when the corresponding ``device`` is provided. If the + array library does not support such cases at all, the function must raise ``BufferError``. If a copy must be made to + enable this support but ``copy`` is set to ``False``, the function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy, and raise ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse the existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data in ``x``. + + .. admonition:: Note + :class: note + + The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array + may raise ``BufferError`` when the data cannot be exported as DLPack + (e.g., incompatible dtype, strides, or device). It may also raise other errors + when export fails for other reasons (e.g., not enough memory available + to materialize the data). ``from_dlpack`` must propagate such + exceptions. + AttributeError + If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present + on the input array. This may happen for libraries that are never able + to export their data with DLPack. + ValueError + If data exchange is possible via an explicit copy but ``copy`` is set to ``False``. + + Notes + ----- + See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in + order to handle DLPack versioning correctly. + + A way to move data from two array libraries to the same device (assumed supported by both libraries) in + a library-agnostic fashion is illustrated below: + + .. code:: python + + def func(x, y): + xp_x = x.__array_namespace__() + xp_y = y.__array_namespace__() + + # Other functions than `from_dlpack` only work if both arrays are from the same library. So if + # `y` is from a different one than `x`, let's convert `y` into an array of the same type as `x`: + if not xp_x == xp_y: + y = xp_x.from_dlpack(y, copy=True, device=x.device) + + # From now on use `xp_x.xxxxx` functions, as both arrays are from the library `xp_x` + ... + + + .. versionchanged:: 2023.12 + Required exceptions to address unsupported use cases. + + .. versionchanged:: 2023.12 + Added device and copy support. + """ + + +def full( + shape: Union[int, Tuple[int, ...]], + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ``fill_value``. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value`` according to the following rules: + + - If the fill value is an ``int``, the output array data type must be the default integer data type. + - If the fill value is a ``float``, the output array data type must be the default real-valued floating-point data type. + - If the fill value is a ``complex`` number, the output array data type must be the default complex floating-point data type. + - If the fill value is a ``bool``, the output array must have a boolean data type. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def full_like( + x: array, + /, + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + + .. note:: + If the ``fill_value`` has a data type which is not of the same data type kind (boolean, integer, or floating-point) as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def linspace( + start: Union[int, float, complex], + stop: Union[int, float, complex], + /, + num: int, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + endpoint: bool = True, +) -> array: + r""" + Returns evenly spaced numbers over a specified interval. + + Let :math:`N` be the number of generated values (which is either ``num`` or ``num+1`` depending on whether ``endpoint`` is ``True`` or ``False``, respectively). For real-valued output arrays, the spacing between values is given by + + .. math:: + \Delta_{\textrm{real}} = \frac{\textrm{stop} - \textrm{start}}{N - 1} + + For complex output arrays, let ``a = real(start)``, ``b = imag(start)``, ``c = real(stop)``, and ``d = imag(stop)``. The spacing between complex values is given by + + .. math:: + \Delta_{\textrm{complex}} = \frac{c-a}{N-1} + \frac{d-b}{N-1} j + + Parameters + ---------- + start: Union[int, float, complex] + the start of the interval. + stop: Union[int, float, complex] + the end of the interval. If ``endpoint`` is ``False``, the function must generate a sequence of ``num+1`` evenly spaced numbers starting with ``start`` and ending with ``stop`` and exclude the ``stop`` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval ``[start, stop)``. If ``endpoint`` is ``True``, the output array must consist of evenly spaced numbers over the closed interval ``[start, stop]``. Default: ``True``. + + .. note:: + The step size changes when `endpoint` is `False`. + + num: int + number of samples. Must be a nonnegative integer value. + dtype: Optional[dtype] + output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, + + - if either ``start`` or ``stop`` is a ``complex`` number, the output data type must be the default complex floating-point data type. + - if both ``start`` and ``stop`` are real-valued, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, conversion of ``start`` and ``stop`` should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + endpoint: bool + boolean indicating whether to include ``stop`` in the interval. Default: ``True``. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. + + Notes + ----- + + .. note:: + While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + + .. note:: + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: + """ + Returns coordinate matrices from coordinate vectors. + + Parameters + ---------- + arrays: array + an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. + indexing: str + Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. + + Returns + ------- + out: List[array] + list of N arrays, where ``N`` is the number of provided one-dimensional input arrays. Each returned array must have rank ``N``. For ``N`` one-dimensional arrays having lengths ``Ni = len(xi)``, + + - if matrix indexing ``ij``, then each returned array must have the shape ``(N1, N2, N3, ..., Nn)``. + - if Cartesian indexing ``xy``, then each returned array must have shape ``(N2, N1, N3, ..., Nn)``. + + Accordingly, for the two-dimensional case with input one-dimensional arrays of length ``M`` and ``N``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M)``. + + Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. + + Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ones. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tril(x: array, /, *, k: int = 0) -> array: + """ + Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The lower triangular part of the matrix is defined as the elements on and below the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal above which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def triu(x: array, /, *, k: int = 0) -> array: + """ + Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The upper triangular part of the matrix is defined as the elements on and above the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal below which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def zeros( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with zeros. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing zeros. + """ + + +def zeros_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with zeros. + """ diff --git a/src/array_api_stubs/_2023_12/data_type_functions.py b/src/array_api_stubs/_2023_12/data_type_functions.py new file mode 100644 index 000000000..e12d349c6 --- /dev/null +++ b/src/array_api_stubs/_2023_12/data_type_functions.py @@ -0,0 +1,228 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + +from ._types import ( + Union, + Tuple, + array, + dtype, + finfo_object, + iinfo_object, + device, + Optional, +) + + +def astype( + x: array, dtype: dtype, /, *, copy: bool = True, device: Optional[device] = None +) -> array: + """ + Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. + + .. note:: + Casting floating-point ``NaN`` and ``infinity`` values to integral data types is not specified and is implementation-dependent. + + .. note:: + Casting a complex floating-point array to a real-valued data type should not be permitted. + + Historically, when casting a complex floating-point array to a real-valued data type, libraries such as NumPy have discarded imaginary components such that, for a complex floating-point array ``x``, ``astype(x)`` equals ``astype(real(x))``). This behavior is considered problematic as the choice to discard the imaginary component is arbitrary and introduces more than one way to achieve the same outcome (i.e., for a complex floating-point array ``x``, ``astype(x)`` and ``astype(real(x))`` versus only ``astype(imag(x))``). Instead, in order to avoid ambiguity and to promote clarity, this specification requires that array API consumers explicitly express which component should be cast to a specified real-valued data type. + + .. note:: + When casting a boolean input array to a real-valued data type, a value of ``True`` must cast to a real-valued number equal to ``1``, and a value of ``False`` must cast to a real-valued number equal to ``0``. + + When casting a boolean input array to a complex floating-point data type, a value of ``True`` must cast to a complex number equal to ``1 + 0j``, and a value of ``False`` must cast to a complex number equal to ``0 + 0j``. + + .. note:: + When casting a real-valued input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. + + When casting a complex floating-point array to ``bool``, a value of ``0 + 0j`` must cast to ``False``, and all other values must cast to ``True``. + + Parameters + ---------- + x: array + array to cast. + dtype: dtype + desired data type. + copy: bool + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + device: Optional[device] + device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Added device keyword argument support. + """ + + +def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: + """ + Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. + + Parameters + ---------- + from_: Union[dtype, array] + input data type or array from which to cast. + to: dtype + desired data type. + + Returns + ------- + out: bool + ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. + """ + + +def finfo(type: Union[dtype, array], /) -> finfo_object: + """ + Machine limits for floating-point data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of floating-point data-type about which to get information. If complex, the information is about its component data type. + + .. note:: + Complex floating-point data types are specified to always use the same precision for both its real and imaginary components, so the information should be true for either component. + + Returns + ------- + out: finfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the real-valued floating-point data type. + + - **eps**: *float* + + difference between 1.0 and the next smallest representable real-valued floating-point number larger than 1.0 according to the IEEE-754 standard. + + - **max**: *float* + + largest representable real-valued number. + + - **min**: *float* + + smallest representable real-valued number. + + - **smallest_normal**: *float* + + smallest positive real-valued floating-point number with full precision. + + - **dtype**: dtype + + real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def iinfo(type: Union[dtype, array], /) -> iinfo_object: + """ + Machine limits for integer data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of integer data-type about which to get information. + + Returns + ------- + out: iinfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the type. + + - **max**: *int* + + largest representable number. + + - **min**: *int* + + smallest representable number. + + - **dtype**: dtype + + integer data type. + + .. versionadded:: 2022.12 + """ + + +def isdtype( + dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]] +) -> bool: + """ + Returns a boolean indicating whether a provided dtype is of a specified data type "kind". + + Parameters + ---------- + dtype: dtype + the input dtype. + kind: Union[str, dtype, Tuple[Union[str, dtype], ...]] + data type kind. + + - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. + - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. + + .. note:: + A conforming implementation of the array API standard is **not** limited to only including the dtypes described in this specification in the required data type kinds. For example, implementations supporting ``float16`` and ``bfloat16`` can include ``float16`` and ``bfloat16`` in the ``real floating`` data type kind. Similarly, implementations supporting ``int128`` can include ``int128`` in the ``signed integer`` data type kind. + + In short, conforming implementations may extend data type kinds; however, data type kinds must remain consistent (e.g., only integer dtypes may belong to integer data type kinds and only floating-point dtypes may belong to floating-point data type kinds), and extensions must be clearly documented as such in library documentation. + + Returns + ------- + out: bool + boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: + """ + Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. + + .. note:: + If provided mixed dtypes (e.g., integer and floating-point), the returned dtype will be implementation-specific. + + Parameters + ---------- + arrays_and_dtypes: Union[array, dtype] + an arbitrary number of input arrays and/or dtypes. + + Returns + ------- + out: dtype + the dtype resulting from an operation involving the input arrays and dtypes. + """ diff --git a/src/array_api_stubs/_2023_12/data_types.py b/src/array_api_stubs/_2023_12/data_types.py new file mode 100644 index 000000000..d15f4a9f7 --- /dev/null +++ b/src/array_api_stubs/_2023_12/data_types.py @@ -0,0 +1,22 @@ +__all__ = ["__eq__"] + + +from ._types import dtype + + +def __eq__(self: dtype, other: dtype, /) -> bool: + """ + Computes the truth value of ``self == other`` in order to test for data type object equality. + + Parameters + ---------- + self: dtype + data type instance. May be any supported data type. + other: dtype + other data type instance. May be any supported data type. + + Returns + ------- + out: bool + a boolean indicating whether the data type objects are equal. + """ diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py new file mode 100644 index 000000000..4462329d6 --- /dev/null +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -0,0 +1,2774 @@ +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "clip", + "conj", + "copysign", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "hypot", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "maximum", + "minimum", + "multiply", + "negative", + "not_equal", + "positive", + "pow", + "real", + "remainder", + "round", + "sign", + "signbit", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] + + +from ._types import Optional, Union, array + + +def abs(x: array, /) -> array: + r""" + Calculates the absolute value for each element ``x_i`` of the input array ``x``. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + .. note:: + For complex floating-point operands, the complex absolute value is known as the norm, modulus, or magnitude and, for a complex number :math:`z = a + bj` is computed as + + .. math:: + \operatorname{abs}(z) = \sqrt{a^2 + b^2} + + .. note:: + For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. + + .. + TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``-0``, the result is ``+0``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``. + - If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``. + - If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``. + - If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acos}(z) = \frac{1}{2}\pi + j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{acos}(z) = \pi - \operatorname{acos}(-z) + + .. note:: + For complex floating-point operands, ``acos(conj(x))`` must equal ``conj(acos(x))``. + + .. note:: + The inverse cosine (or arc cosine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \pi]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``. + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acosh}(z) = \ln(z + \sqrt{z+1}\sqrt{z-1}) + + For any :math:`z`, + + .. math:: + \operatorname{acosh}(z) = \frac{\sqrt{z-1}}{\sqrt{1-z}}\operatorname{acos}(z) + + or simply + + .. math:: + \operatorname{acosh}(z) = j\ \operatorname{acos}(z) + + in the upper half of the complex plane. + + .. note:: + For complex floating-point operands, ``acosh(conj(x))`` must equal ``conj(acosh(x))``. + + .. note:: + The inverse hyperbolic cosine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segment :math:`(-\infty, 1)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic cosine in the interval :math:`[0, \infty)` along the real axis and in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + πj/2``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN ± πj/2`` (sign of imaginary component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def add(x1: array, x2: array, /) -> array: + """ + Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is ``-infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is a nonzero finite number, the result is ``x2_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. + - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. + + .. note:: + Floating-point addition is a commutative operation, but not always associative. + + For complex floating-point operands, addition is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+------------+------------+----------------+ + | | c | dj | c + dj | + +============+============+============+================+ + | **a** | a + c | a + dj | (a+c) + dj | + +------------+------------+------------+----------------+ + | **bj** | c + bj | (b+d)j | c + (b+d)j | + +------------+------------+------------+----------------+ + | **a + bj** | (a+c) + bj | a + (b+d)j | (a+c) + (b+d)j | + +------------+------------+------------+----------------+ + + For complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. For example, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a`` is ``-0`` and ``c`` is ``-0``, the real component of the result is ``-0``. + - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. + + Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def asin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc sine of a complex number :math:`z` is + + .. math:: + \operatorname{asin}(z) = -j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asin}(z) = \operatorname{acos}(-z) - \frac{\pi}{2} + + .. note:: + For complex floating-point operands, ``asin(conj(x))`` must equal ``conj(asin(x))``. + + .. note:: + The inverse sine (or arc sine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse sine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def asinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic sine of a complex number :math:`z` is + + .. math:: + \operatorname{asinh}(z) = \ln(z + \sqrt{1+z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asinh}(z) = \frac{\operatorname{asin}(zj)}{j} + + .. note:: + For complex floating-point operands, ``asinh(conj(x))`` must equal ``conj(asinh(x))`` and ``asinh(-z)`` must equal ``-asinh(z)``. + + .. note:: + The inverse hyperbolic sine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic sine in the range of a strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the inverse tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atan}(z) = -\frac{\ln(1 - zj) - \ln(1 + zj)}{2}j + + .. note:: + For complex floating-point operands, ``atan(conj(x))`` must equal ``conj(atan(x))``. + + .. note:: + The inverse tangent (or arc tangent) is a multi-valued function and requires a branch on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(+j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse tangent in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan2(x1: array, x2: array, /) -> array: + """ + Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. + + The mathematical signs of ``x1_i`` and ``x2_i`` determine the quadrant of each element-wise result. The quadrant (i.e., branch) is chosen such that each element-wise result is the signed angle in radians between the ray ending at the origin and passing through the point ``(1,0)`` and the ray ending at the origin and passing through the point ``(x2_i, x1_i)``. + + .. note:: + Note the role reversal: the "y-coordinate" is the first function parameter; the "x-coordinate" is the second function parameter. The parameter order is intentional and traditional for the two-argument inverse tangent function where the y-coordinate argument is first and the x-coordinate argument is second. + + By IEEE 754 convention, the inverse tangent of the quotient ``x1/x2`` is defined for ``x2_i`` equal to positive or negative zero and for either or both of ``x1_i`` and ``x2_i`` equal to positive or negative ``infinity``. + + Parameters + ---------- + x1: array + input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. + x2: array + input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/4``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. + """ + + +def atanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atanh}(z) = \frac{\ln(1+z)-\ln(z-1)}{2} + + For any :math:`z`, + + .. math:: + \operatorname{atanh}(z) = \frac{\operatorname{atan}(zj)}{j} + + .. note:: + For complex floating-point operands, ``atanh(conj(x))`` must equal ``conj(atanh(x))`` and ``atanh(-x)`` must equal ``-atanh(x)``. + + .. note:: + The inverse hyperbolic tangent is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, 1]` and :math:`[1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic tangent in the range of a half-strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``+1``, the result is ``+infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``1`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def bitwise_and(x1: array, x2: array, /) -> array: + """ + Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_left_shift(x1: array, x2: array, /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. + + Parameters + ---------- + x1: array + first input array. Should have an integer data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_invert(x: array, /) -> array: + """ + Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + """ + + +def bitwise_or(x1: array, x2: array, /) -> array: + """ + Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_right_shift(x1: array, x2: array, /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. + + Parameters + ---------- + x1: array + first input array. Should have an integer data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def bitwise_xor(x1: array, x2: array, /) -> array: + """ + Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have an integer or boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + """ + + +def ceil(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def clip( + x: array, + /, + min: Optional[Union[int, float, array]] = None, + max: Optional[Union[int, float, array]] = None, +) -> array: + r""" + Clamps each element ``x_i`` of the input array ``x`` to the range ``[min, max]``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + min: Optional[Union[int, float, array]] + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + max: Optional[Union[int, float, array]] + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + + Returns + ------- + out: array + an array containing element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. + - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + + .. versionadded:: 2023.12 + """ + + +def conj(x: array, /) -> array: + """ + Returns the complex conjugate for each element ``x_i`` of the input array ``x``. + + For complex numbers of the form + + .. math:: + a + bj + + the complex conjugate is defined as + + .. math:: + a - bj + + Hence, the returned complex conjugates must be computed by negating the imaginary component of each element ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def copysign(x1: array, x2: array, /) -> array: + r""" + Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. + + Parameters + ---------- + x1: array + input array containing magnitudes. Should have a real-valued floating-point data type. + x2: array + input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``-0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``+0``, the result is ``|x1_i|``. + - If ``x2_i`` is greater than ``0``, the result is ``|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. + + If ``x1_i`` is ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + + .. versionadded:: 2023.12 + """ + + +def cos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The cosine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of cosine is + + .. math:: + \begin{align} \operatorname{cos}(x) &= \sum_{n=0}^\infty \frac{(-1)^n}{(2n)!} x^{2n} \\ &= \frac{e^{jx} + e^{-jx}}{2} \\ &= \operatorname{cosh}(jx) \end{align} + + where :math:`\operatorname{cosh}` is the hyperbolic cosine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``NaN``. + - If ``x_i`` is ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic cosine for each element ``x_i`` in the input array ``x``. + + The mathematical definition of the hyperbolic cosine is + + .. math:: + \operatorname{cosh}(x) = \frac{e^x + e^{-x}}{2} + + .. note:: + The hyperbolic cosine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``cosh(x)`` must equal ``cosh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``cosh(conj(x))`` must equal ``conj(cosh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is either ``+0`` or ``-0``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def divide(x1: array, x2: array, /) -> array: + r""" + Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + Parameters + ---------- + x1: array + dividend input array. Should have a numeric data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, division is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a / c | -(a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b/c)j | b/d | special rules | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a/c) + (b/c)j | b/d - (a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division + + .. math:: + \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def equal(x1: array, x2: array, /) -> array: + r""" + Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. May have any data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``False``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` equals ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``False``. + - In the remaining cases, the result is the logical AND of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a == c AND b == d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def exp(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def expm1(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``0 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b) - 1.0``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def floor(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def floor_divide(x1: array, x2: array, /) -> array: + r""" + Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + x1: array + dividend input array. Should have a real-valued data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``\s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + + To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. + + Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. + + This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + """ + + +def greater(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def greater_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def hypot(x1: array, x2: array, /) -> array: + r""" + Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + The value computed by this function may be interpreted as the length of the hypotenuse of a right-angled triangle with sides of length ``x1_i`` and ``x2_i``, the distance of a point ``(x1_i, x2_i)`` from the origin ``(0, 0)``, or the magnitude of a complex number ``x1_i + x2_i * 1j``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``+infinity`` or ``-infinity`` and ``x2_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x2_i`` is ``+infinity`` or ``-infinity`` and ``x1_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x2_i)``. + - If ``x2_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x1_i)``. + - If ``x1_i`` is a finite number or ``NaN`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is a finite number or ``NaN`` and ``x1_i`` is ``NaN``, the result is ``NaN``. + - Underflow may only occur when both arguments are subnormal and the correct result is also subnormal. + + For real-valued floating-point operands, ``hypot(x1, x2)`` must equal ``hypot(x2, x1)``, ``hypot(x1, -x2)``, ``hypot(-x1, x2)``, and ``hypot(-x1, -x2)``. + + .. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, conforming implementations may vary in their support for subnormal numbers. + + .. versionadded:: 2023.12 + """ + + +def imag(x: array, /) -> array: + """ + Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def isfinite(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if finite. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``x_i`` is ``NaN``, the result is ``False``. + - If ``x_i`` is a finite number, the result is ``True``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``False``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. + - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isinf(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. + - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isnan(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array should have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` or ``b`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def less(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def less_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def log(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + The natural logarithm of a complex number :math:`z` with polar coordinates :math:`(r,\theta)` equals :math:`\ln r + (\theta + 2n\pi)j` with principal value :math:`\ln r + \theta j`. + + .. note:: + For complex floating-point operands, ``log(conj(x))`` must equal ``conj(log(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-0`` and ``b`` is ``+0``, the result is ``-infinity + πj``. + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log1p(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-1`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log2(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log2(conj(x))`` must equal ``conj(log2(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log10(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log10(conj(x))`` must equal ``conj(log10(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def logaddexp(x1: array, x2: array, /) -> array: + """ + Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + """ + + +def logical_and(x1: array, x2: array, /) -> array: + """ + Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of `bool`. + """ + + +def logical_not(x: array, /) -> array: + """ + Computes the logical NOT for each element ``x_i`` of the input array ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x: array + input array. Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def logical_or(x1: array, x2: array, /) -> array: + """ + Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def logical_xor(x1: array, x2: array, /) -> array: + """ + Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: array + first input array. Should have a boolean data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def maximum(x1: array, x2: array, /) -> array: + r""" + Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise maximum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + """ + + +def minimum(x1: array, x2: array, /) -> array: + r""" + Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise minimum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + """ + + +def multiply(x1: array, x2: array, /) -> array: + r""" + Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign, the result has a positive mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` and ``x2_i`` have different mathematical signs, the result has a negative mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - In the remaining cases, where neither ``infinity`` nor ``NaN`` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, multiplication is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a * c | (a*d)j | (a*c) + (a*d)j | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b*c)j | -(b*d) | -(b*d) + (b*c)j | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a*c) + (b*c)j | -(b*d) + (a*d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), multiplication of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number multiplication + + .. math:: + (a + bj) \cdot (c + dj) = (ac - bd) + (bc + ad)j + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def negative(x: array, /) -> array: + """ + Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``x`` has a complex floating-point data type, both the real and imaginary components for each ``x_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def not_equal(x1: array, x2: array, /) -> array: + """ + Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. May have any data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``True``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` does not equal ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is the logical OR of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a != c OR b != d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def positive(x: array, /) -> array: + """ + Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pow(x1: array, x2: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. + + .. note:: + If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x1: array + first input array whose elements correspond to the exponentiation base. Should have a numeric data type. + x2: array + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x2_i`` is ``-0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is not equal to ``0``, the result is ``NaN``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``+infinity``, the result is ``1``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``-infinity``, the result is ``1``. + - If ``x1_i`` is ``1`` and ``x2_i`` is not ``NaN``, the result is ``1``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is greater than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + + For complex floating-point operands, special cases should be handled as if the operation is implemented as ``exp(x2*log(x1))``. + + .. note:: + Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def real(x: array, /) -> array: + """ + Returns the real component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def remainder(x1: array, x2: array, /) -> array: + """ + Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This function is equivalent to the Python modulus operator ``x1_i % x2_i``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + x1: array + dividend input array. Should have a real-valued data type. + x2: array + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + In general, similar to Python's ``%`` operator, this function is **not** recommended for floating-point operands as semantics do not follow IEEE 754. That this function is specified to accept floating-point operands is primarily for reasons of backward compatibility. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x2_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - In the remaining cases, the result must match that of the Python ``%`` operator. + """ + + +def round(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. + + .. note:: + For complex floating-point operands, real and imaginary components must be independently rounded to the nearest integer-valued number. + + Rounded real and imaginary components must be equal to their equivalent rounded real-valued floating-point counterparts (i.e., for complex-valued ``x``, ``real(round(x))`` must equal ``round(real(x)))`` and ``imag(round(x))`` must equal ``round(imag(x))``). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + .. note:: + For complex floating-point operands, the following special cases apply to real and imaginary components independently (e.g., if ``real(x_i)`` is ``NaN``, the rounded real component is ``NaN``). + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sign(x: array, /) -> array: + r""" + Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. + + The sign function (also known as the **signum function**) of a number :math:`x_i` is defined as + + .. math:: + \operatorname{sign}(x_i) = \begin{cases} + 0 & \textrm{if } x_i = 0 \\ + \frac{x}{|x|} & \textrm{otherwise} + \end{cases} + + where :math:`|x_i|` is the absolute value of :math:`x_i`. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + For real-valued operands, + + - If ``x_i`` is less than ``0``, the result is ``-1``. + - If ``x_i`` is either ``-0`` or ``+0``, the result is ``0``. + - If ``x_i`` is greater than ``0``, the result is ``+1``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def signbit(x: array, /) -> array: + r""" + Determines whether the sign bit is set for each element ``x_i`` of the input array ``x``. + + The sign bit of a real-valued floating-point number ``x_i`` is set whenever ``x_i`` is either ``-0``, less than zero, or a signed ``NaN`` (i.e., a ``NaN`` value whose sign bit is ``1``). + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``+0``, the result is ``False``. + - If ``x_i`` is ``-0``, the result is ``True``. + - If ``x_i`` is ``+infinity``, the result is ``False``. + - If ``x_i`` is ``-infinity``, the result is ``True``. + - If ``x_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``False``. + - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + + .. versionadded:: 2023.12 + """ + + +def sin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The sine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of sine is + + .. math:: + \begin{align} \operatorname{sin}(x) &= \frac{e^{jx} - e^{-jx}}{2j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \cdot \frac{j}{j} \\ &= -j \cdot \operatorname{sinh}(jx) \end{align} + + where :math:`\operatorname{sinh}` is the hyperbolic sine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic sine for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic sine is + + .. math:: + \operatorname{sinh}(x) = \frac{e^x - e^{-x}}{2} + + .. note:: + The hyperbolic sine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``sinh(x)`` must equal ``-sinh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``sinh(conj(x))`` must equal ``conj(sinh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def square(x: array, /) -> array: + r""" + Squares each element ``x_i`` of the input array ``x``. + + The square of a number ``x_i`` is defined as + + .. math:: + x_i^2 = x_i \cdot x_i + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sqrt(x: array, /) -> array: + r""" + Calculates the principal square root for each element ``x_i`` of the input array ``x``. + + .. note:: + After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). + + .. note:: + For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. + + .. note:: + By convention, the branch cut of the square root is the negative real axis :math:`(-\infty, 0)`. + + The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def subtract(x1: array, x2: array, /) -> array: + """ + Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the tangent for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + Tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the real component and has first order poles along the real line at coordinates :math:`(\pi (\frac{1}{2} + n), 0)`. However, IEEE 754 binary floating-point representation cannot represent the value :math:`\pi / 2` exactly, and, thus, no argument value is possible for which a pole error occurs. + + .. note:: + For complex arguments, the mathematical definition of tangent is + + .. math:: + \begin{align} \operatorname{tan}(x) &= \frac{j(e^{-jx} - e^{jx})}{e^{-jx} + e^{jx}} \\ &= (-1) \frac{j(e^{jx} - e^{-jx})}{e^{jx} + e^{-jx}} \\ &= -j \cdot \operatorname{tanh}(jx) \end{align} + + where :math:`\operatorname{tanh}` is the hyperbolic tangent. + + Parameters + ---------- + x: array + input array whose elements are expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic tangent is + + .. math:: + \begin{align} \operatorname{tanh}(x) &= \frac{\operatorname{sinh}(x)}{\operatorname{cosh}(x)} \\ &= \frac{e^x - e^{-x}}{e^x + e^{-x}} \end{align} + + where :math:`\operatorname{sinh}(x)` is the hyperbolic sine and :math:`\operatorname{cosh}(x)` is the hyperbolic cosine. + + .. note:: + The hyperbolic tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the imaginary component and has first order poles along the imaginary line at coordinates :math:`(0, \pi (\frac{1}{2} + n))`. However, IEEE 754 binary floating-point representation cannot represent :math:`\pi / 2` exactly, and, thus, no argument value is possible such that a pole error occurs. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``tanh(-x)`` must equal ``-tanh(x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+1``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``tanh(conj(x))`` must equal ``conj(tanh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``+0 + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``1 + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. warning:: + For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. + + Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def trunc(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ diff --git a/src/array_api_stubs/_2023_12/fft.py b/src/array_api_stubs/_2023_12/fft.py new file mode 100644 index 000000000..4e8131c8b --- /dev/null +++ b/src/array_api_stubs/_2023_12/fft.py @@ -0,0 +1,683 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + +from ._types import Tuple, Union, Sequence, array, Optional, Literal, device + + +def fft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def fftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + """ + + +def rfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse of ``rfft`` for complex-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def rfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)``, the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse of ``rfftn`` for complex-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def hfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Should have a complex-valued floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + """ + + +def ihfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: + """ + Computes the discrete Fourier transform sample frequencies. + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) # if n is odd + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + """ + + +def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: + """ + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, n/2] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) # if n is odd + + The Nyquist frequency component is considered to be positive. + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + """ + + +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: + """ + Shifts the zero-frequency component to the center of the spectrum. + + This function swaps half-spaces for all axes (dimensions) specified by ``axes``. + + .. note:: + ``out[0]`` is the Nyquist component only if the length of the input is even. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: + """ + Inverse of ``fftshift``. + + .. note:: + Although identical for even-length ``x``, ``fftshift`` and ``ifftshift`` differ by one sample for odd-length ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ diff --git a/src/array_api_stubs/_2023_12/indexing_functions.py b/src/array_api_stubs/_2023_12/indexing_functions.py new file mode 100644 index 000000000..35066a4a2 --- /dev/null +++ b/src/array_api_stubs/_2023_12/indexing_functions.py @@ -0,0 +1,40 @@ +__all__ = ["take"] + +from ._types import Union, Optional, array + + +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: + """ + Returns elements of an array along an axis. + + .. note:: + 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: array + array indices. The array must be one-dimensional and have an integer data type. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + axis: Optional[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 + 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``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Out-of-bounds behavior is explicitly left unspecified. + """ diff --git a/src/array_api_stubs/_2023_12/info.py b/src/array_api_stubs/_2023_12/info.py new file mode 100644 index 000000000..b755ca2c0 --- /dev/null +++ b/src/array_api_stubs/_2023_12/info.py @@ -0,0 +1,197 @@ +__all__ = [ + "__array_namespace_info__", + "capabilities", + "default_device", + "default_dtypes", + "devices", + "dtypes", +] + +from ._types import ( + Optional, + Union, + Tuple, + List, + device, + dtype, + DefaultDataTypes, + DataTypes, + Capabilities, + Info, +) + + +def __array_namespace_info__() -> Info: + """ + Returns a namespace with Array API namespace inspection utilities. + + Returns + ------- + out: Info + An object containing Array API namespace inspection utilities. + + Notes + ----- + + The returned object may be either a namespace or a class, so long as an Array API user can access inspection utilities as follows: + + :: + + info = xp.__array_namespace_info__() + info.capabilities() + info.devices() + info.dtypes() + info.default_dtypes() + # ... + + .. versionadded: 2023.12 + """ + + +def capabilities() -> Capabilities: + """ + Returns a dictionary of array library capabilities. + + The dictionary must contain the following keys: + + - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + + Returns + ------- + out: Capabilities + a dictionary of array library capabilities. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def default_device() -> device: + """ + Returns the default device. + + Returns + ------- + out: device + an object corresponding to the default device. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def default_dtypes( + *, + device: Optional[device] = None, +) -> DefaultDataTypes: + """ + Returns a dictionary containing default data types. + + The dictionary must have the following keys: + + - `"real floating"`: default real floating-point data type. + - `"complex floating"`: default complex floating-point data type. + - `"integral"`: default integral data type. + - `"indexing"`: default array index data type. + + Dictionary values must be the corresponding data type object. + + Parameters + ---------- + device: Optional[device] + device for which to return default data types. If ``device`` is ``None``, the returned data types must be the default data types for the current device; otherwise, the returned data types must be default data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the default data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the default data types for the default device. + + Returns + ------- + out: DefaultDataTypes + a dictionary containing the default data type for respective data type kinds. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def dtypes( + *, + device: Optional[device] = None, + kind: Optional[Union[str, Tuple[str, ...]]] = None, +) -> DataTypes: + """ + Returns a dictionary of supported *Array API* data types. + + .. note:: + While specification-conforming array libraries may support additional data types which are not present in this specification, data types which are not present in this specification should not be included in the returned dictionary. + + .. note:: + Specification-conforming array libraries must only return supported data types having expected properties as described in :ref:`data-types`. For example, if a library decides to alias ``float32`` as ``float64``, that library must not include ``float64`` in the dictionary of supported data types. + + Parameters + ---------- + kind: Optional[Union[str, Tuple[str, ...]]] + data type kind. + + - If ``kind`` is ``None``, the function must return a dictionary containing all supported Array API data types. + + - If ``kind`` is a string, the function must return a dictionary containing the data types belonging to the specified data type kind. The following data type kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of data type kinds, and the function must return a dictionary containing the data types belonging to at least one of the specified data type kinds. + + Default: ``None``. + device: Optional[device] + device for which to return supported data types. If ``device`` is ``None``, the returned data types must be the supported data types for the current device; otherwise, the returned data types must be supported data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the supported data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the supported data types for the default device. + + Returns + ------- + out: DataTypes + a dictionary containing supported data types. + + .. note:: + Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def devices() -> List[device]: + """ + Returns a list of supported devices which are available at runtime. + + Returns + ------- + out: List[device] + a list of supported devices. + + Notes + ----- + + Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + + Notes + ----- + + .. versionadded: 2023.12 + """ diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py new file mode 100644 index 000000000..0950e6937 --- /dev/null +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -0,0 +1,850 @@ +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] + + +from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype +from .constants import inf + + +def cholesky(x: array, /, *, upper: bool = False) -> array: + r""" + Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + + The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = LL^{H} \qquad \text{L $\in\ \mathbb{K}^{n \times n}$} + + where :math:`L` is a lower triangular matrix and :math:`L^{H}` is the conjugate transpose when :math:`L` is complex-valued and the transpose when :math:`L` is real-valued. + + The upper Cholesky decomposition is defined similarly + + .. math:: + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + + where :math:`U` is an upper triangular matrix. + + When ``x`` is a stack of matrices, the function must compute the Cholesky decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square complex Hermitian or real symmetric positive-definite matrices. Should have a floating-point data type. + upper: bool + If ``True``, the result must be the upper-triangular Cholesky factor :math:`U`. If ``False``, the result must be the lower-triangular Cholesky factor :math:`L`. Default: ``False``. + + Returns + ------- + out: array + an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: + """ + Returns the cross product of 3-element vectors. + + If ``x1`` and/or ``x2`` are multi-dimensional arrays (i.e., the broadcasted result has a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. + + Parameters + ---------- + x1: array + first input array. Must have a numeric data type. The size of the axis over which the cross product is to be computed must be equal to 3. + x2: array + second input array. Must be broadcast compatible with ``x1`` along all axes other than the axis along which the cross-product is computed (see :ref:`broadcasting`). The size of the axis over which the cross product is to be computed must be equal to 3. Must have a numeric data type. + + .. note:: + The compute axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted broadcasting to only non-compute axes and required that ``axis`` be a negative integer. + """ + + +def det(x: array, /) -> array: + """ + Returns the determinant of a square matrix (or a stack of square matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def diagonal(x: array, /, *, offset: int = 0) -> array: + """ + Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: `0`. + + Returns + ------- + out: array + an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. + """ + + +def eigh(x: array, /) -> Tuple[array]: + r""" + Returns an eigenvalue decomposition of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalue decomposition** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = Q \Lambda Q^H + + with :math:`Q \in \mathbb{K}^{n \times n}` and :math:`\Lambda \in \mathbb{R}^n` and where :math:`Q^H` is the conjugate transpose when :math:`Q` is complex and the transpose when :math:`Q` is real-valued and :math:`\Lambda` is a diagonal matrix whose diagonal elements are the corresponding eigenvalues. When ``x`` is real-valued, :math:`Q` is orthogonal, and, when ``x`` is complex, :math:`Q` is unitary. + + .. note:: + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. warning:: + The eigenvectors of a symmetric matrix are not unique and are not continuous with respect to ``x``. Because eigenvectors are not unique, different hardware and software may compute different eigenvectors. + + Non-uniqueness stems from the fact that multiplying an eigenvector by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another set of valid eigenvectors. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eig`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array] + a namedtuple (``eigenvalues``, ``eigenvectors``) whose + + - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). + - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def eigvalsh(x: array, /) -> array: + r""" + Returns the eigenvalues of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalues** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` are defined as the roots (counted with multiplicity) of the polynomial :math:`p` of degree :math:`n` given by + + .. math:: + p(\lambda) = \operatorname{det}(x - \lambda I_n) + + where :math:`\lambda \in \mathbb{R}` and where :math:`I_n` is the *n*-dimensional identity matrix. + + .. note:; + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eigvals`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def inv(x: array, /) -> array: + r""" + Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **inverse matrix** :math:`x^{-1} \in\ \mathbb{K}^{n \times n}` of a square matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x^{-1}x = xx^{-1} = I_n + + where :math:`I_n` is the *n*-dimensional identity matrix. + + The inverse matrix exists if and only if ``x`` is invertible. When ``x`` is invertible, the inverse is unique. + + When ``x`` is a stack of matrices, the function must compute the inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matmul(x1: array, x2: array, /) -> array: + """Alias for :func:`~array_api.matmul`.""" + + +def matrix_norm( + x: array, + /, + *, + keepdims: bool = False, + ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro", +) -> array: + """ + Computes the matrix norm of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + keepdims: bool + If ``True``, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the last two axes (dimensions) must not be included in the result. Default: ``False``. + ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] + order of the norm. The following mathematical norms must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | 'fro' | Frobenius norm | + +------------------+---------------------------------+ + | 'nuc' | nuclear norm | + +------------------+---------------------------------+ + | 1 | max(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | 2 | largest singular value | + +------------------+---------------------------------+ + | inf | max(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | -1 | min(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | -2 | smallest singular value | + +------------------+---------------------------------+ + | -inf | min(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + If ``ord=1``, the norm corresponds to the induced matrix norm where ``p=1`` (i.e., the maximum absolute value column sum). + + If ``ord=2``, the norm corresponds to the induced matrix norm where ``p=inf`` (i.e., the maximum absolute value row sum). + + If ``ord=inf``, the norm corresponds to the induced matrix norm where ``p=2`` (i.e., the largest singular value). + + Default: ``'fro'``. + + Returns + ------- + out: array + an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_power(x: array, n: int, /) -> array: + """ + Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + n: int + integer exponent. + + Returns + ------- + out: array + if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + """ + Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). + + When ``x`` is a stack of matrices, the function must compute the number of non-zero singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_transpose(x: array, /) -> array: + """Alias for :func:`~array_api.matrix_transpose`.""" + + +def outer(x1: array, x2: array, /) -> array: + """ + Returns the outer product of two vectors ``x1`` and ``x2``. + + Parameters + ---------- + x1: array + first one-dimensional input array of size ``N``. Must have a numeric data type. + x2: array + second one-dimensional input array of size ``M``. Must have a numeric data type. + + Returns + ------- + out: array + a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + r""" + Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. + + The pseudo-inverse of a matrix :math:`A`, denoted :math:`A^{+}`, is defined as the matrix that "solves" the least-squares problem :math:`Ax = b` (i.e., if :math:`\overline{x}` is a solution, then :math:`A^{+}` is the matrix such that :math:`\overline{x} = A^{+}b`). + + While the pseudo-inverse can be defined algebraically, one can understand the pseudo-inverse via singular value decomposition (SVD). Namely, if + + .. math:: + A = U \Sigma V^H + + is a singular decomposition of :math:`A`, then + + .. math:: + A^{+} = U \Sigma^{+} V^H + + where :math:`U` and :math:`V^H` are orthogonal matrices, :math:`\Sigma` is a diagonal matrix consisting of :math:`A`'s singular values, and :math:`\Sigma^{+}` is then a diagonal matrix consisting of the reciprocals of :math:`A`'s singular values, leaving zeros in place. During numerical computation, only elements larger than a small tolerance are considered nonzero, and all others replaced by zeros. + + When ``x`` is a stack of matrices, the function must compute the pseudo-inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def qr( + x: array, /, *, mode: Literal["reduced", "complete"] = "reduced" +) -> Tuple[array, array]: + r""" + Returns the QR decomposition of a full column rank matrix (or a stack of matrices). + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **complete QR decomposition** of a matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times m}` is orthogonal when ``x`` is real-valued and unitary when ``x`` is complex-valued and where :math:`R \in\ \mathbb{K}^{m \times n}` is an upper triangular matrix with real diagonal (even when ``x`` is complex-valued). + + When :math:`m \gt n` (tall matrix), as :math:`R` is upper triangular, the last :math:`m - n` rows are zero. In this case, the last :math:`m - n` columns of :math:`Q` can be dropped to form the **reduced QR decomposition**. + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. + + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). + + When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. + + .. warning:: + The elements in the diagonal of :math:`R` are not necessarily positive. Accordingly, the returned QR decomposition is only unique up to the sign of the diagonal of :math:`R`, and different libraries or inputs on different devices may produce different valid decompositions. + + .. warning:: + The QR decomposition is only well-defined if the first ``k = min(m,n)`` columns of every matrix in ``x`` are linearly independent. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a floating-point data type. + mode: Literal['reduced', 'complete'] + decomposition mode. Should be one of the following modes: + + - ``'reduced'``: compute only the leading ``K`` columns of ``q``, such that ``q`` and ``r`` have dimensions ``(..., M, K)`` and ``(..., K, N)``, respectively, and where ``K = min(M, N)``. + - ``'complete'``: compute ``q`` and ``r`` with dimensions ``(..., M, M)`` and ``(..., M, N)``, respectively. + + Default: ``'reduced'``. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(Q, R)`` whose + + - first element must have the field name ``Q`` and must be an array whose shape depends on the value of ``mode`` and contain matrices with orthonormal columns. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, M)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input array ``x``. + - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. + + Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def slogdet(x: array, /) -> Tuple[array, array]: + r""" + Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. + + .. note:: + The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling ``det`` may overflow or underflow. + + The sign of the determinant is given by + + .. math:: + \operatorname{sign}(\det x) = \begin{cases} + 0 & \textrm{if } \det x = 0 \\ + \frac{\det x}{|\det x|} & \textrm{otherwise} + \end{cases} + + where :math:`|\det x|` is the absolute value of the determinant of ``x``. + + When ``x`` is a stack of matrices, the function must compute the sign and natural logarithm of the absolute value of the determinant for each matrix in the stack. + + **Special Cases** + + For real-valued floating-point operands, + + - If the determinant is zero, the ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``. + + For complex floating-point operands, + + - If the determinant is ``0 + 0j``, the ``sign`` should be ``0 + 0j`` and ``logabsdet`` should be ``-infinity + 0j``. + + .. note:: + Depending on the underlying algorithm, when the determinant is zero, the returned result may differ from ``-infinity`` (or ``-infinity + 0j``). In all cases, the determinant should be equal to ``sign * exp(logabsdet)`` (although, again, the result may be subject to numerical precision errors). + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array, array] + a namedtuple (``sign``, ``logabsdet``) whose + + - first element must have the field name ``sign`` and must be an array containing a number representing the sign of the determinant for each square matrix. Must have the same data type as ``x``. + - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). + + Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def solve(x1: array, x2: array, /) -> array: + r""" + Returns the solution of a square system of linear equations with a unique solution. + + Let ``x1`` equal :math:`A` and ``x2`` equal :math:`B`. If the promoted data type of ``x1`` and ``x2`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if the promoted data type of ``x1`` and ``x2`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + This function computes the solution :math:`X \in\ \mathbb{K}^{m \times k}` of the **linear system** associated to :math:`A \in\ \mathbb{K}^{m \times m}` and :math:`B \in\ \mathbb{K}^{m \times k}` and is defined as + + .. math:: + AX = B + + This system of linear equations has a unique solution if and only if :math:`A` is invertible. + + .. note:: + Whether an array library explicitly checks whether ``x1`` is invertible is implementation-defined. + + When ``x1`` and/or ``x2`` is a stack of matrices, the function must compute a solution for each matrix in the stack. + + Parameters + ---------- + x1: array + coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. + x2: array + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: + r""" + Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The full **singular value decomposition** of an :math:`m \times n` matrix :math:`x \in\ \mathbb{K}^{m \times n}` is a factorization of the form + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times m}`, :math:`\Sigma \in\ \mathbb{K}^{m \times\ n}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}` with :math:`k = \operatorname{min}(m, n)`, :math:`V^H \in\ \mathbb{K}^{n \times n}`, and where :math:`V^H` is the conjugate transpose when :math:`V` is complex and the transpose when :math:`V` is real-valued. When ``x`` is real-valued, :math:`U`, :math:`V` (and thus :math:`V^H`) are orthogonal, and, when ``x`` is complex, :math:`U`, :math:`V` (and thus :math:`V^H`) are unitary. + + When :math:`m \gt n` (tall matrix), we can drop the last :math:`m - n` columns of :math:`U` to form the reduced SVD + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times k}`, :math:`\Sigma \in\ \mathbb{K}^{k \times\ k}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}`, and :math:`V^H \in\ \mathbb{K}^{k \times n}`. In this case, :math:`U` and :math:`V` have orthonormal columns. + + Similarly, when :math:`n \gt m` (wide matrix), we can drop the last :math:`n - m` columns of :math:`V` to also form a reduced SVD. + + This function returns the decomposition :math:`U`, :math:`S`, and :math:`V^H`, where :math:`S = \operatorname{diag}(\Sigma)`. + + When ``x`` is a stack of matrices, the function must compute the singular value decomposition for each matrix in the stack. + + .. warning:: + The returned arrays :math:`U` and :math:`V` are neither unique nor continuous with respect to ``x``. Because :math:`U` and :math:`V` are not unique, different hardware and software may compute different singular vectors. + + Non-uniqueness stems from the fact that multiplying any pair of singular vectors :math:`u_k`, :math:`v_k` by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another two valid singular vectors of the matrix. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + full_matrices: bool + If ``True``, compute full-sized ``U`` and ``Vh``, such that ``U`` has shape ``(..., M, M)`` and ``Vh`` has shape ``(..., N, N)``. If ``False``, compute on the leading ``K`` singular vectors, such that ``U`` has shape ``(..., M, K)`` and ``Vh`` has shape ``(..., K, N)`` and where ``K = min(M, N)``. Default: ``True``. + + Returns + ------- + out: Tuple[array, array, array] + a namedtuple ``(U, S, Vh)`` whose + + - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). + - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def svdvals(x: array, /) -> array: + """ + Returns the singular values of a matrix (or a stack of matrices) ``x``. + + When ``x`` is a stack of matrices, the function must compute the singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + + Returns + ------- + out: array + an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """Alias for :func:`~array_api.tensordot`.""" + + +def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> array: + """ + Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a numeric data type. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: ``0``. + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + Returns + ------- + out: array + an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if ``x`` has rank ``k`` and shape ``(I, J, K, ..., L, M, N)``, then an output array has rank ``k-2`` and shape ``(I, J, K, ..., L)`` where + + :: + + out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) + + The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: + """Alias for :func:`~array_api.vecdot`.""" + + +def vector_norm( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, + ord: Union[int, float, Literal[inf, -inf]] = 2, +) -> array: + r""" + Computes the vector norm of a vector (or batch of vectors) ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + If an integer, ``axis`` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, ``axis`` specifies the axes (dimensions) along which to compute batched vector norms. If ``None``, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: ``None``. + keepdims: bool + If ``True``, the axes (dimensions) specified by ``axis`` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the axes (dimensions) specified by ``axis`` must not be included in the result. Default: ``False``. + ord: Union[int, float, Literal[inf, -inf]] + order of the norm. The following mathematical norms must be supported: + + +------------------+----------------------------+ + | ord | description | + +==================+============================+ + | 1 | L1-norm (Manhattan) | + +------------------+----------------------------+ + | 2 | L2-norm (Euclidean) | + +------------------+----------------------------+ + | inf | infinity norm | + +------------------+----------------------------+ + | (int,float >= 1) | p-norm | + +------------------+----------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+--------------------------------+ + | ord | description | + +==================+================================+ + | 0 | sum(a != 0) | + +------------------+--------------------------------+ + | -1 | 1./sum(1./abs(a)) | + +------------------+--------------------------------+ + | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | + +------------------+--------------------------------+ + | -inf | min(abs(a)) | + +------------------+--------------------------------+ + | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | + +------------------+--------------------------------+ + + Default: ``2``. + + Returns + ------- + out: array + an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ diff --git a/src/array_api_stubs/_2023_12/linear_algebra_functions.py b/src/array_api_stubs/_2023_12/linear_algebra_functions.py new file mode 100644 index 000000000..da4c97743 --- /dev/null +++ b/src/array_api_stubs/_2023_12/linear_algebra_functions.py @@ -0,0 +1,166 @@ +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] + + +from ._types import Tuple, Union, Sequence, array + + +def matmul(x1: array, x2: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + x2: array + second input array. Should have a numeric data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``x1`` and ``x2`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``x1`` is a one-dimensional array having shape ``(K,)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``x1`` or ``x2`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(x1)[:-2]`` against ``shape(x2)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + + The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + **Raises** + + - if either ``x1`` or ``x2`` is a zero-dimensional array. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + + """ + + +def matrix_transpose(x: array, /) -> array: + """ + Transposes a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + + Returns + ------- + out: array + an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """ + Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. + + .. note:: + The ``tensordot`` function corresponds to the generalized matrix product. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Should have a numeric data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + + .. note:: + Contracted axes (dimensions) must not be broadcasted. + + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] + number of axes (dimensions) to contract or explicit sequences of axis (dimension) indices for ``x1`` and ``x2``, respectively. + + If ``axes`` is an ``int`` equal to ``N``, then contraction must be performed over the last ``N`` axes of ``x1`` and the first ``N`` axes of ``x2`` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. + + - If ``N`` equals ``0``, the result is the tensor (outer) product. + - If ``N`` equals ``1``, the result is the tensor dot product. + - If ``N`` equals ``2``, the result is the tensor double contraction (default). + + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each index referred to in a sequence must be unique. If ``x1`` has rank (i.e, number of dimensions) ``N``, a valid ``x1`` axis must reside on the half-open interval ``[-N, N)``. If ``x2`` has rank ``M``, a valid ``x2`` axis must reside on the half-open interval ``[-M, M)``. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the generalized matrix product. + + Returns + ------- + out: array + an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Allow negative axes. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: + r""" + Computes the (vector) dot product of two arrays. + + Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as + + .. math:: + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i + + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. + + Parameters + ---------- + x1: array + first input array. Should have a floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). The size of the axis over which to compute the dot product must be the same size as the respective axis in ``x1``. Should have a floating-point data type. + + .. note:: + The contracted axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the dot product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted ``axis`` to only negative integers. + """ diff --git a/src/array_api_stubs/_2023_12/manipulation_functions.py b/src/array_api_stubs/_2023_12/manipulation_functions.py new file mode 100644 index 000000000..87f9511b0 --- /dev/null +++ b/src/array_api_stubs/_2023_12/manipulation_functions.py @@ -0,0 +1,368 @@ +__all__ = [ + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "moveaxis", + "permute_dims", + "repeat", + "reshape", + "roll", + "squeeze", + "stack", + "tile", + "unstack", +] + + +from ._types import List, Optional, Tuple, Union, array + + +def broadcast_arrays(*arrays: array) -> List[array]: + """ + Broadcasts one or more arrays against one another. + + Parameters + ---------- + arrays: array + an arbitrary number of to-be broadcasted arrays. + + Returns + ------- + out: List[array] + a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. + """ + + +def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: + """ + Broadcasts an array to a specified shape. + + Parameters + ---------- + x: array + array to broadcast. + shape: Tuple[int, ...] + array shape. Must be compatible with ``x`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + + Returns + ------- + out: array + an array having a specified shape. Must have the same data type as ``x``. + """ + + +def concat( + arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0 +) -> array: + """ + Joins a sequence of arrays along an existing axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. The arrays must have the same shape, except in the dimension specified by ``axis``. + axis: Optional[int] + axis along which the arrays will be joined. If ``axis`` is ``None``, arrays must be flattened before concatenation. If ``axis`` is negative, the function must determine the axis along which to join by counting from the last dimension. Default: ``0``. + + Returns + ------- + out: array + an output array containing the concatenated values. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def expand_dims(x: array, /, *, axis: int = 0) -> array: + """ + Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. + + Parameters + ---------- + x: array + input array. + axis: int + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). + + Returns + ------- + out: array + an expanded output array having the same data type as ``x``. + + Raises + ------ + IndexError + If provided an invalid ``axis`` position, an ``IndexError`` should be raised. + """ + + +def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + """ + Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which to flip. If ``axis`` is ``None``, the function must flip all input array axes. If ``axis`` is negative, the function must count from the last dimension. If provided more than one axis, the function must flip only the specified axes. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. + """ + + +def moveaxis( + x: array, + source: Union[int, Tuple[int, ...]], + destination: Union[int, Tuple[int, ...]], + /, +) -> array: + """ + Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. + + Parameters + ---------- + x: array + input array. + source: Union[int, Tuple[int, ...]] + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + destination: Union[int, Tuple[int, ...]] + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + + Returns + ------- + out: array + an array containing reordered axes. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: + """ + Permutes the axes (dimensions) of an array ``x``. + + Parameters + ---------- + x: array + input array. + axes: Tuple[int, ...] + tuple containing a permutation of ``(0, 1, ..., N-1)`` where ``N`` is the number of axes (dimensions) of ``x``. + + Returns + ------- + out: array + an array containing the axes permutation. The returned array must have the same data type as ``x``. + """ + + +def repeat( + x: array, + repeats: Union[int, array], + /, + *, + axis: Optional[int] = None, +) -> array: + """ + Repeats each element of an array a specified number of times on a per-element basis. + + .. admonition:: Data-dependent output shape + :class: important + + When ``repeats`` is an array, the shape of the output array for this function depends on the data values in the ``repeats`` array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing the values in ``repeats``. Accordingly, such libraries may choose to omit support for ``repeats`` arrays; however, conforming implementations must support providing a literal ``int``. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array containing elements to repeat. + repeats: Union[int, array] + the number of repetitions for each element. + + If ``axis`` is ``None``, let ``N = prod(x.shape)`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(N,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(N,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape `(N,)`. + + If ``axis`` is not ``None``, let ``M = x.shape[axis]`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(M,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(M,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape ``(M,)``. + + If ``repeats`` is an array, the array must have an integer data type. + + .. note:: + For specification-conforming array libraries supporting hardware acceleration, providing an array for ``repeats`` may cause device synchronization due to an unknown output shape. For those array libraries where synchronization concerns are applicable, conforming array libraries are advised to include a warning in their documentation regarding potential performance degradation when ``repeats`` is an array. + + axis: Optional[int] + the axis (dimension) along which to repeat elements. If ``axis`` is `None`, the function must flatten the input array ``x`` and then repeat elements of the flattened input array and return the result as a one-dimensional output array. A flattened input array must be flattened in row-major, C-style order. Default: ``None``. + + Returns + ------- + out: array + an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def reshape( + x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None +) -> array: + """ + Reshapes an array without changing its data. + + Parameters + ---------- + x: array + input array to reshape. + shape: Tuple[int, ...] + a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. + copy: Optional[bool] + whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If ``copy=False`` and a copy would be necessary, a ``ValueError`` + should be raised. + """ + + +def roll( + x: array, + /, + shift: Union[int, Tuple[int, ...]], + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, +) -> array: + """ + Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. + + Parameters + ---------- + x: array + input array. + shift: Union[int, Tuple[int, ...]] + number of places by which the elements are shifted. If ``shift`` is a tuple, then ``axis`` must be a tuple of the same size, and each of the given axes must be shifted by the corresponding element in ``shift``. If ``shift`` is an ``int`` and ``axis`` a tuple, then the same ``shift`` must be used for all specified axes. If a shift is positive, then array elements must be shifted positively (toward larger indices) along the dimension of ``axis``. If a shift is negative, then array elements must be shifted negatively (toward smaller indices) along the dimension of ``axis``. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which elements to shift. If ``axis`` is ``None``, the array must be flattened, shifted, and then restored to its original shape. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. + """ + + +def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: + """ + Removes singleton dimensions (axes) from ``x``. + + Parameters + ---------- + x: array + input array. + axis: Union[int, Tuple[int, ...]] + axis (or axes) to squeeze. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If a specified axis has a size greater than one (i.e., it is not a + singleton dimension), a ``ValueError`` should be raised. + """ + + +def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: + """ + Joins a sequence of arrays along a new axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. Each array must have the same shape. + axis: int + axis along which the arrays will be joined. Providing an ``axis`` specifies the index of the new axis in the dimensions of the result. For example, if ``axis`` is ``0``, the new axis will be the first dimension and the output array will have shape ``(N, A, B, C)``; if ``axis`` is ``1``, the new axis will be the second dimension and the output array will have shape ``(A, N, B, C)``; and, if ``axis`` is ``-1``, the new axis will be the last dimension and the output array will have shape ``(A, B, C, N)``. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: array + an output array having rank ``N+1``, where ``N`` is the rank (number of dimensions) of ``x``. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def tile(x: array, repetitions: Tuple[int, ...], /): + """ + Constructs an array by tiling an input array. + + Parameters + ---------- + x: array + input array. + repetitions: Tuple[int, ...] + number of repetitions along each axis (dimension). + + Let ``N = len(x.shape)`` and ``M = len(repetitions)``. + + If ``N > M``, the function must prepend ones until all axes (dimensions) are specified (e.g., if ``x`` has shape ``(8,6,4,2)`` and ``repetitions`` is the tuple ``(3,3)``, then ``repetitions`` must be treated as ``(1,1,3,3)``). + + If ``N < M``, the function must prepend singleton axes (dimensions) to ``x`` until ``x`` has as many axes (dimensions) as ``repetitions`` specifies (e.g., if ``x`` has shape ``(4,2)`` and ``repetitions`` is the tuple ``(3,3,3,3)``, then ``x`` must be treated as if it has shape ``(1,1,4,2)``). + + Returns + ------- + out: array + a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: + """ + Splits an array in a sequence of arrays along the given axis. + + Parameters + ---------- + x: array + input array. + axis: int + axis along which the array will be split. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: Tuple[array, ...] + tuple of slices along the given dimension. All the arrays have the same shape. + + Notes + ----- + + .. versionadded:: 2023.12 + """ diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py new file mode 100644 index 000000000..029459b9a --- /dev/null +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -0,0 +1,159 @@ +__all__ = ["argmax", "argmin", "nonzero", "searchsorted", "where"] + + +from ._types import Optional, Tuple, Literal, array + + +def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the maximum values along a specified axis. + + When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the maximum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. + """ + + +def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the minimum values along a specified axis. + + When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the minimum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. + """ + + +def nonzero(x: array, /) -> Tuple[array, ...]: + """ + Returns the indices of the array elements which are non-zero. + + .. note:: + If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + + .. note:: + If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. admonition:: Data-dependent output shape + :class: admonition important + + The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array. Must have a positive rank. If ``x`` is zero-dimensional, the function must raise an exception. + + Returns + ------- + out: Typle[array, ...] + a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def searchsorted( + x1: array, + x2: array, + /, + *, + side: Literal["left", "right"] = "left", + sorter: Optional[array] = None, +) -> array: + """ + Finds the indices into ``x1`` such that, if the corresponding elements in ``x2`` were inserted before the indices, the order of ``x1``, when sorted in ascending order, would be preserved. + + Parameters + ---------- + x1: array + input array. Must be a one-dimensional array. Should have a real-valued data type. If ``sorter`` is ``None``, must be sorted in ascending order; otherwise, ``sorter`` must be an array of indices that sort ``x1`` in ascending order. + x2: array + array containing search values. Should have a real-valued data type. + side: Literal['left', 'right'] + argument controlling which index is returned if a value lands exactly on an edge. + + Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + + If ``side == 'left'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``0``. + + Otherwise, if ``side == 'right'``, then + + - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. + - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + + Default: ``'left'``. + sorter: Optional[array] + array of indices that sort ``x1`` in ascending order. The array must have the same shape as ``x1`` and have an integer data type. Default: ``None``. + + Returns + ------- + out: array + an array of indices with the same shape as ``x2``. The returned array must have the default array index data type. + + Notes + ----- + + For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. + + While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + + .. versionadded:: 2023.12 + """ + + +def where(condition: array, x1: array, x2: array, /) -> array: + """ + Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. + + Parameters + ---------- + condition: array + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + x1: array + first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). + x2: array + second input array. Must be compatible with ``condition`` and ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. + """ diff --git a/src/array_api_stubs/_2023_12/set_functions.py b/src/array_api_stubs/_2023_12/set_functions.py new file mode 100644 index 000000000..5b7e9a56c --- /dev/null +++ b/src/array_api_stubs/_2023_12/set_functions.py @@ -0,0 +1,183 @@ +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] + + +from ._types import Tuple, array + + +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``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array, array, array] + a namedtuple ``(values, indices, inverse_indices, counts)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of a flattened ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. + - third element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and must have the default array index data type. + - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_counts(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple `(values, counts)` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_inverse(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(values, inverse_indices)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior. + """ + + +def unique_values(x: array, /) -> array: + """ + Returns the unique elements of an input array ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: array + a one-dimensional array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required that the output array must be one-dimensional. + """ diff --git a/src/array_api_stubs/_2023_12/sorting_functions.py b/src/array_api_stubs/_2023_12/sorting_functions.py new file mode 100644 index 000000000..2dc4ac410 --- /dev/null +++ b/src/array_api_stubs/_2023_12/sorting_functions.py @@ -0,0 +1,58 @@ +__all__ = ["argsort", "sort"] + + +from ._types import array + + +def argsort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns the indices that sort an array ``x`` along a specified axis. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x : array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the returned indices sort ``x`` in descending order (by value). If ``False``, the returned indices sort ``x`` in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned indices must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned indices may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. + """ + + +def sort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns a sorted copy of an input array ``x``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the array must be sorted in descending order (by value). If ``False``, the array must be sorted in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned array must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned array may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + a sorted array. The returned array must have the same data type and shape as ``x``. + """ diff --git a/src/array_api_stubs/_2023_12/statistical_functions.py b/src/array_api_stubs/_2023_12/statistical_functions.py new file mode 100644 index 000000000..9d3563e26 --- /dev/null +++ b/src/array_api_stubs/_2023_12/statistical_functions.py @@ -0,0 +1,374 @@ +__all__ = ["cumulative_sum", "max", "mean", "min", "prod", "std", "sum", "var"] + + +from ._types import Optional, Tuple, Union, array, dtype + + +def cumulative_sum( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative sum of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum 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. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative sum. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative sum must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionadded:: 2023.12 + """ + + +def max( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the maximum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def mean( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the arithmetic mean of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the arithmetic mean. + + - If ``N`` is ``0``, the arithmetic mean is ``NaN``. + - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). + """ + + +def min( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the minimum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def prod( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the product of input array ``x`` elements. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the product. + + - If ``N`` is ``0``, the product is `1` (i.e., the empty product). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def std( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the standard deviation of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which standard deviations must be computed. By default, the standard deviation must be computed over the entire array. If a tuple of integers, standard deviations must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the standard deviation according to ``N-c`` where ``N`` corresponds to the total number of elements over which the standard deviation is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the standard deviation of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the corrected sample standard deviation, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the standard deviation. + + - If ``N - correction`` is less than or equal to ``0``, the standard deviation is ``NaN``. + - If ``x_i`` is ``NaN``, the standard deviation is ``NaN`` (i.e., ``NaN`` values propagate). + """ + + +def sum( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the sum of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def var( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the variance of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which variances must be computed. By default, the variance must be computed over the entire array. If a tuple of integers, variances must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the variance according to ``N-c`` where ``N`` corresponds to the total number of elements over which the variance is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the variance of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the unbiased sample variance, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the same data type as ``x``. + + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the variance. + + - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. + - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). + """ diff --git a/src/array_api_stubs/_2023_12/utility_functions.py b/src/array_api_stubs/_2023_12/utility_functions.py new file mode 100644 index 000000000..81d8dca41 --- /dev/null +++ b/src/array_api_stubs/_2023_12/utility_functions.py @@ -0,0 +1,86 @@ +__all__ = ["all", "any"] + + +from ._types import Optional, Tuple, Union, array + + +def all( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether all input array elements evaluate to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``True``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical AND reduction. By default, a logical AND reduction must be performed over the entire array. If a tuple of integers, logical AND reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def any( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether any input array element evaluates to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``False``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical OR reduction. By default, a logical OR reduction must be performed over the entire array. If a tuple of integers, logical OR reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index 4ac3783ef..ca9122e7f 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1 +1 @@ -from . import _2021_12, _2022_12, _draft +from . import _2021_12, _2022_12, _2023_12, _draft From ef81ddf066a3505c72baf7812364d18b9a4c728f Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:08:12 -0800 Subject: [PATCH 493/551] Empty commit for draft at 2023.12 From 2f95e0bb8132419fb500f4221d7027c9f66f74bd Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:11:52 -0800 Subject: [PATCH 494/551] build: update list of ignored files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d4f538406..cc40a3b43 100644 --- a/.gitignore +++ b/.gitignore @@ -34,3 +34,4 @@ tmp/ *.egg-info/ *.egg dist/ +.DS_STORE From f63e9fddec99d37827e7339ea02e01203e774f2d Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Mon, 26 Feb 2024 00:12:31 -0800 Subject: [PATCH 495/551] chore: remove files --- .DS_Store | Bin 6148 -> 0 bytes src/.DS_Store | Bin 6148 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store delete mode 100644 src/.DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index cb2845bfd45fe0b2d4e5d60af22acccb797086ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~F$w}f3`G;&V!>uh%V|7-Hy9Q@ffo=|Y(z!TdXDZ-CJ3(9BJu;tpJXO1`-+{7 zh-iP?&P6&AY2l_avoJ74-pEzXvXjkybvYhR$31FRAH`W)!#f%5$2NroNPq-LfCNb3 zhX~lc4QnS=8A*TyNZ?7pz7Gj*nnO!f|8yYu2mozRcEj3d323qcG>4X|sK7L)2aQ(s zF~sWL4oz_`hnA|fT{MOdjVG&3F)*#|q6rC1vkLuHq@&4g1L!&>UK-q5|WOfMZ}Ffv*yH E03NCmz5oCK diff --git a/src/.DS_Store b/src/.DS_Store deleted file mode 100644 index dd19daea5d1a7b84e37b40dd1eb49bfc451dd50b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKOG-mQ5UkcL0xrzbzd)!;&mE;Ee}t(zyiRW?uaiBQ}gHU6T7I45$QbR6ZhEQ9WTW5%(>U(?D*S^_)rPCZTp zSWi@x0#abCz-4Y1-v96DC+7b#NjoVZ1^$%+He0P%OTJR|*2&9xuWj@Py4QTu-M9`4 nL$qUJv}10(9p6Mz)-_-Ac`qCigU)==iTX3(y2zx!Un}qfHa!=x From fa04c35c87708fa565a4a8f6bb8360ae836ac5d7 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Thu, 29 Feb 2024 06:07:32 +0100 Subject: [PATCH 496/551] Bump Sphinx and sphinx-material versions to latest releases (#757) --- doc-requirements.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc-requirements.txt b/doc-requirements.txt index 08ced9aa2..5c0effdb8 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -1,5 +1,5 @@ -sphinx==6.2.1 -sphinx-material==0.0.30 +sphinx==7.2.6 +sphinx-material==0.0.36 myst-parser sphinx_markdown_tables sphinx_copybutton From c305b82a05fe85e47ea26b7ef61fb299b23f7ed6 Mon Sep 17 00:00:00 2001 From: Ralf Gommers Date: Tue, 5 Mar 2024 16:53:57 +0100 Subject: [PATCH 497/551] Fix version switcher by using sphinxcontrib-jquery (#758) Note that this doesn't work on local doc builds, it'll now give: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///path/to/array-api/_site/versions.json. (Reason: CORS request not http) --- doc-requirements.txt | 1 + src/_array_api_conf.py | 1 + 2 files changed, 2 insertions(+) diff --git a/doc-requirements.txt b/doc-requirements.txt index 5c0effdb8..3e31808f2 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -5,3 +5,4 @@ sphinx_markdown_tables sphinx_copybutton sphinx_favicon sphinx-math-dollar +sphinxcontrib-jquery diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index ec5d56d58..08929cc43 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -36,6 +36,7 @@ "sphinx_copybutton", "sphinx_favicon", "sphinx_markdown_tables", + "sphinxcontrib.jquery", ] autosummary_generate = True From 630149c51d8ec6dff62678eaec454c519a1d87dd Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 21 Mar 2024 02:21:31 -0700 Subject: [PATCH 498/551] docs: fix equation rendering in `linalg.cholesky` (#762) Closes: https://github.com/data-apis/array-api/issues/761 --- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_2023_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index a2207bb4c..7996d7472 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -6,7 +6,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: r""" Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. - If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py index 0950e6937..49cce7160 100644 --- a/src/array_api_stubs/_2023_12/linalg.py +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -33,7 +33,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: r""" Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. - If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 0950e6937..49cce7160 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -33,7 +33,7 @@ def cholesky(x: array, /, *, upper: bool = False) -> array: r""" Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. - If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers $\mathbb{R}$, and, if ``x`` is complex-valued, let $\mathbb{K}$ be the set of complex numbers $\mathbb{C}$. + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as From 91ff864decaef09a7fcca28a4b65de3c5f765d5f Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 4 Apr 2024 03:57:11 -0600 Subject: [PATCH 499/551] docs: fix typo in the changelog PR-URL: https://github.com/data-apis/array-api/pull/767 Reviewed-by: Athan Reines --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eace3f0a1..5d69bbc23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -89,7 +89,7 @@ The following is a list of breaking changes relative to the previous version of - `prod`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) - `sum`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) -- `vecdot`: only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) +- `vecdot`: only require a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) #### Extensions @@ -104,7 +104,7 @@ The following is a list of breaking changes in specification extensions relative - `fft.irfftn`: require the output array have a real-valued floating-point data type having the same precision as the input array ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) - `fft.fftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) - `fft.rfftfreq`: require the output array have the default real-valued floating-point data type ([gh-720](https://github.com/data-apis/array-api/pull/720); backported to v2022.12 revision of Array API specification) -- `linalg.cross`: broadcast only along non-compute axes and only allow a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) +- `linalg.cross`: broadcast only along non-compute axes and only require a negative integer for the `axis` keyword argument ([gh-740](https://github.com/data-apis/array-api/pull/740)) - `linalg.trace`: when provided a floating-point array, the function must return a floating-point array having the same data type ([gh-744](https://github.com/data-apis/array-api/pull/744)) * * * From 65d3102c5210310c74c73147e751c4c567e56bb1 Mon Sep 17 00:00:00 2001 From: Meekail Zain <34613774+Micky774@users.noreply.github.com> Date: Tue, 9 Apr 2024 21:55:39 -0400 Subject: [PATCH 500/551] Corrected typo in `__bool__` with backport (#785) --- src/array_api_stubs/_2022_12/array_object.py | 2 +- src/array_api_stubs/_2023_12/array_object.py | 2 +- src/array_api_stubs/_draft/array_object.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index b8f703996..f00df850b 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -237,7 +237,7 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. - For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. .. versionchanged:: 2022.12 Added boolean and complex data type support. diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index 6dd70c278..d71a26293 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -239,7 +239,7 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. - For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. **Lazy implementations** diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 6dd70c278..d71a26293 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -239,7 +239,7 @@ def __bool__(self: array, /) -> bool: - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. - For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical AND of ``bool(real(self))`` and ``bool(imag(self))``. + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. **Lazy implementations** From 63633e7f0484c7afafa66b051a7d2bc75a1b0bab Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 25 Apr 2024 15:42:45 -0600 Subject: [PATCH 501/551] Add missing return type hint to tile() (#798) * Add missing return type hint to tile() * Add tile type signature fix to the draft version --- src/array_api_stubs/_2023_12/manipulation_functions.py | 2 +- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2023_12/manipulation_functions.py b/src/array_api_stubs/_2023_12/manipulation_functions.py index 87f9511b0..7d5111135 100644 --- a/src/array_api_stubs/_2023_12/manipulation_functions.py +++ b/src/array_api_stubs/_2023_12/manipulation_functions.py @@ -316,7 +316,7 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ -def tile(x: array, repetitions: Tuple[int, ...], /): +def tile(x: array, repetitions: Tuple[int, ...], /) -> array: """ Constructs an array by tiling an input array. diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 87f9511b0..7d5111135 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -316,7 +316,7 @@ def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> """ -def tile(x: array, repetitions: Tuple[int, ...], /): +def tile(x: array, repetitions: Tuple[int, ...], /) -> array: """ Constructs an array by tiling an input array. From 69e2733e003803eb992dc7524c3805fd06d5a0c1 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Tue, 30 Apr 2024 16:12:28 -0600 Subject: [PATCH 502/551] build: fix requirements to work with conda pip treats dashes and underscores the same but conda does not. The package names here are actually dashes (pip just replaces an underscore with a dash) so this is more correct anyway. PR-URL: https://github.com/data-apis/array-api/pull/800 Reviewed-by: Athan Reines --- doc-requirements.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc-requirements.txt b/doc-requirements.txt index 3e31808f2..15ef0b245 100644 --- a/doc-requirements.txt +++ b/doc-requirements.txt @@ -1,8 +1,8 @@ sphinx==7.2.6 sphinx-material==0.0.36 myst-parser -sphinx_markdown_tables -sphinx_copybutton -sphinx_favicon +sphinx-markdown-tables +sphinx-copybutton +sphinx-favicon sphinx-math-dollar sphinxcontrib-jquery From 6a5767aebf512385a783b7631039398738253332 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 1 May 2024 21:01:57 -0700 Subject: [PATCH 503/551] feat: add `max rank` to inspection API capabilities PR-URL: https://github.com/data-apis/array-api/pull/763 Closes: https://github.com/data-apis/array-api/issues/694 Reviewed-by: Ralf Gommers Reviewed-by: Leo Fang --- src/array_api_stubs/_draft/_types.py | 7 ++++++- src/array_api_stubs/_draft/info.py | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/_types.py b/src/array_api_stubs/_draft/_types.py index 7c3d903d7..f2fa356f2 100644 --- a/src/array_api_stubs/_draft/_types.py +++ b/src/array_api_stubs/_draft/_types.py @@ -140,5 +140,10 @@ def dtypes( total=False, ) Capabilities = TypedDict( - "Capabilities", {"boolean indexing": bool, "data-dependent shapes": bool} + "Capabilities", + { + "boolean indexing": bool, + "data-dependent shapes": bool, + "max rank": Optional[int], + }, ) diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index b755ca2c0..e9eb66cf1 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -56,6 +56,7 @@ def capabilities() -> Capabilities: - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"max rank"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. Returns ------- From cee41670d93a73c0132dd3e2a943107bea28ecff Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 1 May 2024 21:50:36 -0700 Subject: [PATCH 504/551] feat: add `nextafter` to specification PR-URL: https://github.com/data-apis/array-api/pull/792 Closes: https://github.com/data-apis/array-api/issues/664 Reviewed-by: Ralf Gommers --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 30 +++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index 4919cff98..a853ca18c 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -66,6 +66,7 @@ Objects in API minimum multiply negative + nextafter not_equal positive pow diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 4462329d6..ec0b0567c 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -48,6 +48,7 @@ "minimum", "multiply", "negative", + "nextafter", "not_equal", "positive", "pow", @@ -2069,6 +2070,35 @@ def negative(x: array, /) -> array: """ +def nextafter(x1: array, x2: array, /) -> array: + """ + Returns the next representable floating-point value for each element ``x1_i`` of the input array ``x1`` in the direction of the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: array + first input array. Should have a real-valued floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have the same data type as ``x1``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x1``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``-0``. + """ + + def not_equal(x1: array, x2: array, /) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. From 25e717735b72c6b55080f48af634015d94833838 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 22 May 2024 05:07:29 -0600 Subject: [PATCH 505/551] Fixes to the array-api stubs (#806) * Replace info with __array_namespace_info__ in the stubs 'info' is not an actual top-level name in the namespace. * Use consistent wording for complex dtypes in the fft stubs * Fix some copysign special-cases for better machine readability and consistency --- src/array_api_stubs/_2022_12/fft.py | 14 +++++------ src/array_api_stubs/_2023_12/__init__.py | 2 +- .../_2023_12/elementwise_functions.py | 14 +++++------ src/array_api_stubs/_2023_12/fft.py | 24 +++++++++---------- src/array_api_stubs/_draft/__init__.py | 2 +- .../_draft/elementwise_functions.py | 14 +++++------ src/array_api_stubs/_draft/fft.py | 24 +++++++++---------- 7 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/array_api_stubs/_2022_12/fft.py b/src/array_api_stubs/_2022_12/fft.py index bdd7a9c83..f6fb3627a 100644 --- a/src/array_api_stubs/_2022_12/fft.py +++ b/src/array_api_stubs/_2022_12/fft.py @@ -35,7 +35,7 @@ def fft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -84,7 +84,7 @@ def ifft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -133,7 +133,7 @@ def fftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -188,7 +188,7 @@ def ifftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -292,7 +292,7 @@ def irfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -398,7 +398,7 @@ def irfftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. @@ -452,7 +452,7 @@ def hfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. diff --git a/src/array_api_stubs/_2023_12/__init__.py b/src/array_api_stubs/_2023_12/__init__.py index 8415f2765..537ea8f85 100644 --- a/src/array_api_stubs/_2023_12/__init__.py +++ b/src/array_api_stubs/_2023_12/__init__.py @@ -16,7 +16,7 @@ from .utility_functions import * from . import linalg from . import fft -from . import info +from .info import __array_namespace_info__ __array_api_version__: str = "YYYY.MM" diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 4462329d6..2d4847195 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -874,14 +874,12 @@ def copysign(x1: array, x2: array, /) -> array: - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. - If ``x1_i`` is ``NaN``, - - - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_2023_12/fft.py b/src/array_api_stubs/_2023_12/fft.py index 4e8131c8b..7a4538ccb 100644 --- a/src/array_api_stubs/_2023_12/fft.py +++ b/src/array_api_stubs/_2023_12/fft.py @@ -35,7 +35,7 @@ def fft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -66,7 +66,7 @@ def fft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -87,7 +87,7 @@ def ifft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -118,7 +118,7 @@ def ifft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -139,7 +139,7 @@ def fftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -176,7 +176,7 @@ def fftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -197,7 +197,7 @@ def ifftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -234,7 +234,7 @@ def ifftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -304,7 +304,7 @@ def irfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -413,7 +413,7 @@ def irfftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. @@ -470,7 +470,7 @@ def hfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -501,7 +501,7 @@ def hfft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + Required the input array to have a complex floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. """ diff --git a/src/array_api_stubs/_draft/__init__.py b/src/array_api_stubs/_draft/__init__.py index 8415f2765..537ea8f85 100644 --- a/src/array_api_stubs/_draft/__init__.py +++ b/src/array_api_stubs/_draft/__init__.py @@ -16,7 +16,7 @@ from .utility_functions import * from . import linalg from . import fft -from . import info +from .info import __array_namespace_info__ __array_api_version__: str = "YYYY.MM" diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index ec0b0567c..bd0fd8083 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -875,14 +875,12 @@ def copysign(x1: array, x2: array, /) -> array: - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. - If ``x1_i`` is ``NaN``, - - - If ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. - - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 4e8131c8b..7a4538ccb 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -35,7 +35,7 @@ def fft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -66,7 +66,7 @@ def fft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -87,7 +87,7 @@ def ifft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. @@ -118,7 +118,7 @@ def ifft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -139,7 +139,7 @@ def fftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -176,7 +176,7 @@ def fftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -197,7 +197,7 @@ def ifftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. @@ -234,7 +234,7 @@ def ifftn( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array have a complex-valued floating-point data type and required that the output array have the same data type as the input array. + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. """ @@ -304,7 +304,7 @@ def irfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -413,7 +413,7 @@ def irfftn( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. s: Optional[Sequence[int]] number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. @@ -470,7 +470,7 @@ def hfft( Parameters ---------- x: array - input array. Should have a complex-valued floating-point data type. + input array. Should have a complex floating-point data type. n: Optional[int] number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. @@ -501,7 +501,7 @@ def hfft( .. versionadded:: 2022.12 .. versionchanged:: 2023.12 - Required the input array to have a complex-valued floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + Required the input array to have a complex floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. """ From b569b039612eed2993471c129d2ab95b3d7ea95e Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 25 Jul 2024 09:41:58 -0700 Subject: [PATCH 506/551] feat: add `reciprocal` to the specification PR-URL: https://github.com/data-apis/array-api/pull/802 Closes: https://github.com/data-apis/array-api/issues/790 --- .../elementwise_functions.rst | 1 + .../_draft/elementwise_functions.py | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/spec/draft/API_specification/elementwise_functions.rst b/spec/draft/API_specification/elementwise_functions.rst index a853ca18c..9758c68db 100644 --- a/spec/draft/API_specification/elementwise_functions.rst +++ b/spec/draft/API_specification/elementwise_functions.rst @@ -71,6 +71,7 @@ Objects in API positive pow real + reciprocal remainder round sign diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index bd0fd8083..c9d5e2953 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -53,6 +53,7 @@ "positive", "pow", "real", + "reciprocal", "remainder", "round", "sign", @@ -2252,6 +2253,29 @@ def real(x: array, /) -> array: """ +def reciprocal(x: array, /) -> array: + """ + Returns the reciprocal for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``1.0 / x`` (see :func:`~array_api.divide`). + """ + + def remainder(x1: array, x2: array, /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. From b93391545a8d3e4099a10bac5215bf04680c8d9a Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 25 Jul 2024 10:55:58 -0600 Subject: [PATCH 507/551] docs: clarify broadcasting semantics and output shape in `linalg.solve` (#810) PR-URL: https://github.com/data-apis/array-api/pull/810 --- src/array_api_stubs/_2022_12/linalg.py | 4 ++-- src/array_api_stubs/_2023_12/linalg.py | 4 ++-- src/array_api_stubs/_2023_12/manipulation_functions.py | 2 +- src/array_api_stubs/_draft/linalg.py | 4 ++-- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index 7996d7472..b13a5bf01 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -594,12 +594,12 @@ def solve(x1: array, x2: array, /) -> array: x1: array coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. Notes ----- diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py index 49cce7160..a1c9fe028 100644 --- a/src/array_api_stubs/_2023_12/linalg.py +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -623,12 +623,12 @@ def solve(x1: array, x2: array, /) -> array: x1: array coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. Notes ----- diff --git a/src/array_api_stubs/_2023_12/manipulation_functions.py b/src/array_api_stubs/_2023_12/manipulation_functions.py index 7d5111135..131b81eb3 100644 --- a/src/array_api_stubs/_2023_12/manipulation_functions.py +++ b/src/array_api_stubs/_2023_12/manipulation_functions.py @@ -347,7 +347,7 @@ def tile(x: array, repetitions: Tuple[int, ...], /) -> array: def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: """ - Splits an array in a sequence of arrays along the given axis. + Splits an array into a sequence of arrays along the given axis. Parameters ---------- diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index 49cce7160..a1c9fe028 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -623,12 +623,12 @@ def solve(x1: array, x2: array, /) -> array: x1: array coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. x2: array - ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-1]`` must be compatible with ``shape(x1)[:-1]`` (see :ref:`broadcasting`). Should have a floating-point data type. + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. Returns ------- out: array - an array containing the solution to the system ``AX = B`` for each square matrix. The returned array must have the same shape as ``x2`` (i.e., the array corresponding to ``B``) and must have a floating-point data type determined by :ref:`type-promotion`. + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. Notes ----- diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 7d5111135..131b81eb3 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -347,7 +347,7 @@ def tile(x: array, repetitions: Tuple[int, ...], /) -> array: def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: """ - Splits an array in a sequence of arrays along the given axis. + Splits an array into a sequence of arrays along the given axis. Parameters ---------- From 6bfea7ab9b54b5862aa8a3ec6d8b1f4496b2e79b Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 25 Jul 2024 11:00:22 -0600 Subject: [PATCH 508/551] feat!: rename "max rank" to "max dimensions" in `capabilities()` PR-URL: https://github.com/data-apis/array-api/pull/809 Ref: https://github.com/data-apis/array-api/pull/763#issuecomment-2138355341 --- src/array_api_stubs/_draft/info.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index e9eb66cf1..1815a71e9 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -56,7 +56,7 @@ def capabilities() -> Capabilities: - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. - - `"max rank"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. + - `"max dimensions"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. Returns ------- From b2e232b7b687ff201bab1565254c81ec2f428110 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 15 Aug 2024 16:16:30 -0600 Subject: [PATCH 509/551] docs: cross-link to the inspection page in `__array_namespace_info__` PR-URL: https://github.com/data-apis/array-api/pull/836 Reviewed-by: Athan Reines --- spec/2023.12/API_specification/inspection.rst | 2 ++ spec/draft/API_specification/inspection.rst | 2 ++ src/array_api_stubs/_2023_12/info.py | 2 ++ src/array_api_stubs/_draft/info.py | 2 ++ 4 files changed, 8 insertions(+) diff --git a/spec/2023.12/API_specification/inspection.rst b/spec/2023.12/API_specification/inspection.rst index 04691e712..89d9c602a 100644 --- a/spec/2023.12/API_specification/inspection.rst +++ b/spec/2023.12/API_specification/inspection.rst @@ -1,3 +1,5 @@ +.. _inspection: + Inspection ========== diff --git a/spec/draft/API_specification/inspection.rst b/spec/draft/API_specification/inspection.rst index 04691e712..89d9c602a 100644 --- a/spec/draft/API_specification/inspection.rst +++ b/spec/draft/API_specification/inspection.rst @@ -1,3 +1,5 @@ +.. _inspection: + Inspection ========== diff --git a/src/array_api_stubs/_2023_12/info.py b/src/array_api_stubs/_2023_12/info.py index b755ca2c0..507c853c9 100644 --- a/src/array_api_stubs/_2023_12/info.py +++ b/src/array_api_stubs/_2023_12/info.py @@ -25,6 +25,8 @@ def __array_namespace_info__() -> Info: """ Returns a namespace with Array API namespace inspection utilities. + See :ref:`inspection` for a list of inspection APIs. + Returns ------- out: Info diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index 1815a71e9..6177fb12f 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -25,6 +25,8 @@ def __array_namespace_info__() -> Info: """ Returns a namespace with Array API namespace inspection utilities. + See :ref:`inspection` for a list of inspection APIs. + Returns ------- out: Info From 0cd4bdf6a8f1b3ca62c0d0c480b60a16467bd999 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Mon, 26 Aug 2024 19:53:23 -0700 Subject: [PATCH 510/551] docs: fix reference to eigh/eigvalsh PR-URL: https://github.com/data-apis/array-api/pull/838 Reviewed-by: Athan Reines --- spec/2021.12/extensions/linear_algebra_functions.rst | 4 ++-- spec/2022.12/extensions/linear_algebra_functions.rst | 4 ++-- spec/2023.12/extensions/linear_algebra_functions.rst | 4 ++-- spec/draft/extensions/linear_algebra_functions.rst | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/2021.12/extensions/linear_algebra_functions.rst b/spec/2021.12/extensions/linear_algebra_functions.rst index dbe643bed..de24d5a0b 100644 --- a/spec/2021.12/extensions/linear_algebra_functions.rst +++ b/spec/2021.12/extensions/linear_algebra_functions.rst @@ -48,8 +48,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. diff --git a/spec/2022.12/extensions/linear_algebra_functions.rst b/spec/2022.12/extensions/linear_algebra_functions.rst index 6759b2260..938221c79 100644 --- a/spec/2022.12/extensions/linear_algebra_functions.rst +++ b/spec/2022.12/extensions/linear_algebra_functions.rst @@ -51,8 +51,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. diff --git a/spec/2023.12/extensions/linear_algebra_functions.rst b/spec/2023.12/extensions/linear_algebra_functions.rst index 6759b2260..938221c79 100644 --- a/spec/2023.12/extensions/linear_algebra_functions.rst +++ b/spec/2023.12/extensions/linear_algebra_functions.rst @@ -51,8 +51,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. diff --git a/spec/draft/extensions/linear_algebra_functions.rst b/spec/draft/extensions/linear_algebra_functions.rst index 6759b2260..938221c79 100644 --- a/spec/draft/extensions/linear_algebra_functions.rst +++ b/spec/draft/extensions/linear_algebra_functions.rst @@ -51,8 +51,8 @@ Accordingly, the standardization process affords the opportunity to reduce inter In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: - - ``eig``: computing both eigenvalues and eignvectors. - - ``eigvals``: computing only eigenvalues. + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. 4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. From 45b705de8e20a30487f1d369112a26428b5ab418 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Sep 2024 23:01:08 -0700 Subject: [PATCH 511/551] feat: add `diff` to specification PR-URL: https://github.com/data-apis/array-api/pull/791 Closes: https://github.com/data-apis/array-api/issues/784 --- .../API_specification/utility_functions.rst | 1 + .../_draft/utility_functions.py | 44 ++++++++++++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/utility_functions.rst b/spec/draft/API_specification/utility_functions.rst index 5105fa3df..a09c99f79 100644 --- a/spec/draft/API_specification/utility_functions.rst +++ b/spec/draft/API_specification/utility_functions.rst @@ -20,3 +20,4 @@ Objects in API all any + diff diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index 81d8dca41..cdbe4a0f8 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -1,4 +1,4 @@ -__all__ = ["all", "any"] +__all__ = ["all", "any", "diff"] from ._types import Optional, Tuple, Union, array @@ -84,3 +84,45 @@ def any( .. versionchanged:: 2022.12 Added complex data type support. """ + + +def diff( + x: array, + /, + *, + axis: int = -1, + n: int = 1, + prepend: Optional[array] = None, + append: Optional[array] = None, +) -> array: + """ + Calculates the n-th discrete forward difference along a specified axis. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: int + axis along which to compute differences. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute differences by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``-1``. + n: int + number of times to recursively compute differences. Default: ``1``. + prepend: Optional[array] + values to prepend to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + append: Optional[array] + values to append to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + + Returns + ------- + out: array + an array containing the n-th differences. Should have the same data type as ``x``. Must have the same shape as ``x``, except for the axis specified by ``axis`` which must have a size determined as follows: + + - Let ``M`` be the number of elements along an axis specified by ``axis``. + - Let ``N1`` be the number of prepended values along an axis specified by ``axis``. + - Let ``N2`` be the number of appended values along an axis specified by ``axis``. + - The final size of the axis specified by ``axis`` must be ``M + N1 + N2 - n``. + + Notes + ----- + + - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). + """ From 8b0e405cdbe5d56a9705bc6a1d6b534554e29d64 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 19 Sep 2024 00:06:55 -0600 Subject: [PATCH 512/551] docs: specify the behavior of `clip()` when one of the operands is NaN PR-URL: https://github.com/data-apis/array-api/pull/813 Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2023_12/elementwise_functions.py | 6 ++++++ src/array_api_stubs/_draft/elementwise_functions.py | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 2d4847195..4739ab674 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -807,6 +807,12 @@ def clip( - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + **Special cases** + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``min_i`` is ``NaN``, the result is ``NaN``. + - If ``max_i`` is ``NaN``, the result is ``NaN``. + .. versionadded:: 2023.12 """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index c9d5e2953..78a76b37d 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -809,6 +809,12 @@ def clip( - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + **Special cases** + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``min_i`` is ``NaN``, the result is ``NaN``. + - If ``max_i`` is ``NaN``, the result is ``NaN``. + .. versionadded:: 2023.12 """ From b877795060f9b5ba519507ccf453af516ec11f9f Mon Sep 17 00:00:00 2001 From: "hpkfft.com" Date: Wed, 18 Sep 2024 23:26:22 -0700 Subject: [PATCH 513/551] docs: clarify `roundTiesToEven` behavior for non-ties PR-URL: https://github.com/data-apis/array-api/pull/825 Reviewed-by: Athan Reines --- spec/draft/design_topics/accuracy.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/draft/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst index 8c97db698..61a2c49aa 100644 --- a/spec/draft/design_topics/accuracy.rst +++ b/spec/draft/design_topics/accuracy.rst @@ -23,7 +23,7 @@ including the corresponding element-wise array APIs defined in this standard - multiply - divide -for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., ties rounded toward the nearest value with an even least significant bit). +for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). Mathematical Functions ---------------------- From 390e9ccd27a0ee635c253a2b7acb2e338caf2c95 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 18 Sep 2024 23:36:12 -0700 Subject: [PATCH 514/551] feat: add `take_long_axis` to specifiation PR-URL: https://github.com/data-apis/array-api/pull/816 Closes: https://github.com/data-apis/array-api/issues/808 --- .../API_specification/indexing_functions.rst | 1 + .../_draft/indexing_functions.py | 26 ++++++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/indexing_functions.rst b/spec/draft/API_specification/indexing_functions.rst index aef298566..c13e55ecf 100644 --- a/spec/draft/API_specification/indexing_functions.rst +++ b/spec/draft/API_specification/indexing_functions.rst @@ -21,3 +21,4 @@ Objects in API :template: method.rst take + take_along_axis diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 35066a4a2..a9b38b482 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -1,4 +1,4 @@ -__all__ = ["take"] +__all__ = ["take", "take_along_axis"] from ._types import Union, Optional, array @@ -38,3 +38,27 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. versionchanged:: 2023.12 Out-of-bounds behavior is explicitly left unspecified. """ + + +def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: + """ + Returns elements from an array at the one-dimensional indices specified by ``indices`` along a provided ``axis``. + + Parameters + ---------- + x: array + input array. Must be compatible with ``indices``, except for the axis (dimension) specified by ``axis`` (see :ref:`broadcasting`). + indices: array + array indices. Must have the same rank (i.e., number of dimensions) as ``x``. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + axis: int + axis along 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. Default: ``-1``. + + Returns + ------- + out: array + an array having the same data type as ``x``. Must have the same rank (i.e., number of dimensions) as ``x`` and must have a shape determined according to :ref:`broadcasting`, except for the axis (dimension) specified by ``axis`` whose size must equal the size of the corresponding axis (dimension) in ``indices``. + """ From 1765933ad23c4dc3be3ff0b29d89e47f38739432 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Wed, 30 Oct 2024 20:30:12 -0700 Subject: [PATCH 515/551] docs: add missing subscripts in `sign` definition PR-URL: https://github.com/data-apis/array-api/pull/844 Reviewed-by: Athan Reines Reviewed-by: Oleksandr Pavlyk --- src/array_api_stubs/_2022_12/elementwise_functions.py | 2 +- src/array_api_stubs/_2023_12/elementwise_functions.py | 2 +- src/array_api_stubs/_draft/elementwise_functions.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2022_12/elementwise_functions.py b/src/array_api_stubs/_2022_12/elementwise_functions.py index 9139612e8..fe0f5f2b1 100644 --- a/src/array_api_stubs/_2022_12/elementwise_functions.py +++ b/src/array_api_stubs/_2022_12/elementwise_functions.py @@ -2065,7 +2065,7 @@ def sign(x: array, /) -> array: .. math:: \operatorname{sign}(x_i) = \begin{cases} 0 & \textrm{if } x_i = 0 \\ - \frac{x}{|x|} & \textrm{otherwise} + \frac{x_i}{|x_i|} & \textrm{otherwise} \end{cases} where :math:`|x_i|` is the absolute value of :math:`x_i`. diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 4739ab674..251a770d6 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -2335,7 +2335,7 @@ def sign(x: array, /) -> array: .. math:: \operatorname{sign}(x_i) = \begin{cases} 0 & \textrm{if } x_i = 0 \\ - \frac{x}{|x|} & \textrm{otherwise} + \frac{x_i}{|x_i|} & \textrm{otherwise} \end{cases} where :math:`|x_i|` is the absolute value of :math:`x_i`. diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 78a76b37d..3f4c08898 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -2389,7 +2389,7 @@ def sign(x: array, /) -> array: .. math:: \operatorname{sign}(x_i) = \begin{cases} 0 & \textrm{if } x_i = 0 \\ - \frac{x}{|x|} & \textrm{otherwise} + \frac{x_i}{|x_i|} & \textrm{otherwise} \end{cases} where :math:`|x_i|` is the absolute value of :math:`x_i`. From c28d3c576a90281a3f713a1e53e0565f430e1647 Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 30 Oct 2024 22:18:04 -0600 Subject: [PATCH 516/551] docs: add note that iteration is defined for 1-D arrays PR-URL: https://github.com/data-apis/array-api/pull/821 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_2021_12/array_object.py | 4 ++++ src/array_api_stubs/_2022_12/array_object.py | 4 ++++ src/array_api_stubs/_2023_12/array_object.py | 4 ++++ src/array_api_stubs/_draft/array_object.py | 8 ++++++++ 4 files changed, 20 insertions(+) diff --git a/src/array_api_stubs/_2021_12/array_object.py b/src/array_api_stubs/_2021_12/array_object.py index 528e0a286..07bd2c3e3 100644 --- a/src/array_api_stubs/_2021_12/array_object.py +++ b/src/array_api_stubs/_2021_12/array_object.py @@ -465,6 +465,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -914,6 +916,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index f00df850b..83abc9310 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -489,6 +489,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -937,6 +939,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index d71a26293..5c0b10dd9 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -616,6 +616,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -1085,6 +1087,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index d71a26293..dcd1c53fa 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -616,6 +616,8 @@ def __getitem__( """ Returns ``self[key]``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array @@ -627,6 +629,10 @@ def __getitem__( ------- out: array an array containing the accessed value(s). The returned array must have the same data type as ``self``. + + .. note:: + When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + """ def __gt__(self: array, other: Union[int, float, array], /) -> array: @@ -1085,6 +1091,8 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. + See :ref:`indexing` for details on supported indexing semantics. + Parameters ---------- self: array From 6d205d72dde3db8fc8668ad6aef5d003cc8ef80f Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Wed, 30 Oct 2024 22:55:16 -0600 Subject: [PATCH 517/551] docs: add note that cross-kind comparisons are undefined PR-URL: https://github.com/data-apis/array-api/pull/822 Closes: https://github.com/data-apis/array-api/issues/819 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/array_object.py | 18 ++++++++++++++++++ .../_draft/elementwise_functions.py | 19 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index dcd1c53fa..3c6fa8763 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -513,6 +513,9 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __float__(self: array, /) -> float: @@ -599,6 +602,9 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __getitem__( @@ -657,6 +663,9 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __index__(self: array, /) -> int: @@ -778,6 +787,9 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -823,6 +835,9 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __matmul__(self: array, other: array, /) -> array: @@ -949,6 +964,9 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + .. versionchanged:: 2022.12 Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 3f4c08898..156715200 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -1125,6 +1125,9 @@ def equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + .. versionchanged:: 2022.12 Added complex data type support. """ @@ -1354,6 +1357,10 @@ def greater(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + """ @@ -1375,6 +1382,9 @@ def greater_equal(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ @@ -1570,6 +1580,9 @@ def less(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ @@ -1591,6 +1604,9 @@ def less_equal(x1: array, x2: array, /) -> array: ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ @@ -2141,6 +2157,9 @@ def not_equal(x1: array, x2: array, /) -> array: .. note:: For discussion of complex number equality, see :ref:`complex-numbers`. + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + .. versionchanged:: 2022.12 Added complex data type support. """ From a7bcfe6932f71f508460257214058b8a3aef81f7 Mon Sep 17 00:00:00 2001 From: minerharry <35383543+minerharry@users.noreply.github.com> Date: Mon, 2 Dec 2024 04:56:03 -0500 Subject: [PATCH 518/551] Update copies_views_and_mutation.rst (#865) word order typo --- spec/draft/design_topics/copies_views_and_mutation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/draft/design_topics/copies_views_and_mutation.rst b/spec/draft/design_topics/copies_views_and_mutation.rst index 52be1c805..1ca5a039c 100644 --- a/spec/draft/design_topics/copies_views_and_mutation.rst +++ b/spec/draft/design_topics/copies_views_and_mutation.rst @@ -6,7 +6,7 @@ Copy-view behaviour and mutability .. admonition:: Mutating views :class: important - Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may be either a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. + Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may either be a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically have the concept of a "view", meaning an array containing data in memory that From 05ec5e72b0fe7b63f9822ede7b20a5108b7b20d3 Mon Sep 17 00:00:00 2001 From: Matt Haberland Date: Wed, 11 Dec 2024 11:29:12 -0800 Subject: [PATCH 519/551] docs: clarify that implementations may add additional arguments (#870) --- spec/draft/purpose_and_scope.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/draft/purpose_and_scope.md b/spec/draft/purpose_and_scope.md index f375c9512..b2019b7dd 100644 --- a/spec/draft/purpose_and_scope.md +++ b/spec/draft/purpose_and_scope.md @@ -410,8 +410,8 @@ all the functions, arguments, data types, syntax, and semantics described in this specification. A conforming implementation of the array API standard may provide additional -values, objects, properties, data types, and functions beyond those described -in this specification. +features (e.g., values, objects, properties, data types, functions, and function +arguments) beyond those described in this specification. Libraries which aim to provide a conforming implementation but haven't yet completed such an implementation may, and are encouraged to, provide details on From 5cdcf75b66647a45374656605b66c9e922cfe01c Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 01:13:14 -0800 Subject: [PATCH 520/551] docs: add note regarding unspecified behavior for 0d arrays in `cumulative_sum` PR-URL: https://github.com/data-apis/array-api/pull/851 Closes: https://github.com/data-apis/array-api/issues/797 --- src/array_api_stubs/_draft/statistical_functions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 9d3563e26..4cb6de0a8 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -18,7 +18,7 @@ def cumulative_sum( Parameters ---------- x: array - input array. Should have a numeric data type. + input array. Should have one or more dimensions (axes). Should have a numeric data type. axis: Optional[int] axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum by counting from the last dimension. @@ -48,6 +48,8 @@ def cumulative_sum( Notes ----- + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + **Special Cases** For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. From 5ffffeed9afc5643215bc051662c3647de4e8a3e Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 02:02:44 -0800 Subject: [PATCH 521/551] feat: add `count_nonzero` to specification PR-URL: https://github.com/data-apis/array-api/pull/803 Closes: https://github.com/data-apis/array-api/issues/794 --- .../API_specification/searching_functions.rst | 1 + .../_draft/searching_functions.py | 47 +++++++++++++++---- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/spec/draft/API_specification/searching_functions.rst b/spec/draft/API_specification/searching_functions.rst index c952f1aad..1a584f158 100644 --- a/spec/draft/API_specification/searching_functions.rst +++ b/spec/draft/API_specification/searching_functions.rst @@ -22,6 +22,7 @@ Objects in API argmax argmin + count_nonzero nonzero searchsorted where diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 029459b9a..4eee3173b 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -1,7 +1,7 @@ -__all__ = ["argmax", "argmin", "nonzero", "searchsorted", "where"] +__all__ = ["argmax", "argmin", "count_nonzero", "nonzero", "searchsorted", "where"] -from ._types import Optional, Tuple, Literal, array +from ._types import Optional, Tuple, Literal, Union, array def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: @@ -54,15 +54,41 @@ def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) - """ -def nonzero(x: array, /) -> Tuple[array, ...]: +def count_nonzero( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: """ - Returns the indices of the array elements which are non-zero. + Counts the number of array elements which are non-zero. - .. note:: - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to count non-zero values. By default, the number of non-zero values must be computed over the entire array. If a tuple of integers, the number of non-zero values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. - .. note:: - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + Returns + ------- + out: array + if the number of non-zeros values was computed over the entire array, a zero-dimensional array containing the total number of non-zero values; otherwise, a non-zero-dimensional array containing the counts along the specified axes. The returned array must have the default array index data type. + + Notes + ----- + + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + """ + + +def nonzero(x: array, /) -> Tuple[array, ...]: + """ + Returns the indices of the array elements which are non-zero. .. admonition:: Data-dependent output shape :class: admonition important @@ -76,12 +102,15 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. Notes ----- + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + .. versionchanged:: 2022.12 Added complex data type support. """ From c492972ffe6db9911ffaeb222962b7ca5f916919 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 02:14:05 -0800 Subject: [PATCH 522/551] feat: add `cumulative_prod` specification PR-URL: https://github.com/data-apis/array-api/pull/793 Closes: https://github.com/data-apis/array-api/issues/598 --- .../statistical_functions.rst | 1 + .../_draft/statistical_functions.py | 64 ++++++++++++++++++- 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/spec/draft/API_specification/statistical_functions.rst b/spec/draft/API_specification/statistical_functions.rst index 20e02b3f9..eb5e1a5d6 100644 --- a/spec/draft/API_specification/statistical_functions.rst +++ b/spec/draft/API_specification/statistical_functions.rst @@ -18,6 +18,7 @@ Objects in API :toctree: generated :template: method.rst + cumulative_prod cumulative_sum max mean diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 4cb6de0a8..347a97fff 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -1,9 +1,71 @@ -__all__ = ["cumulative_sum", "max", "mean", "min", "prod", "std", "sum", "var"] +__all__ = [ + "cumulative_sum", + "cumulative_prod", + "max", + "mean", + "min", + "prod", + "std", + "sum", + "var", +] from ._types import Optional, Tuple, Union, array, dtype +def cumulative_prod( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative product of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative product must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative product 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. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the multiplicative identity (i.e., one). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative product. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative product must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + """ + + def cumulative_sum( x: array, /, From f7d16ff6516be1704f5ec00bdcdd808a90babdd7 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Thu, 12 Dec 2024 11:21:55 +0000 Subject: [PATCH 523/551] fix: clarify that `condition` should have a boolean dtype in `where` PR-URL: https://github.com/data-apis/array-api/pull/868 Ref: https://github.com/data-apis/array-api/pull/116 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2021_12/searching_functions.py | 2 +- src/array_api_stubs/_2022_12/searching_functions.py | 2 +- src/array_api_stubs/_2023_12/searching_functions.py | 2 +- src/array_api_stubs/_draft/searching_functions.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2021_12/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py index 14ebdd889..ca7d22420 100644 --- a/src/array_api_stubs/_2021_12/searching_functions.py +++ b/src/array_api_stubs/_2021_12/searching_functions.py @@ -69,7 +69,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py index 9dcc0f95c..2d2560502 100644 --- a/src/array_api_stubs/_2022_12/searching_functions.py +++ b/src/array_api_stubs/_2022_12/searching_functions.py @@ -91,7 +91,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py index 029459b9a..9d64fe6da 100644 --- a/src/array_api_stubs/_2023_12/searching_functions.py +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -146,7 +146,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 4eee3173b..9e0053825 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -175,7 +175,7 @@ def where(condition: array, x1: array, x2: array, /) -> array: Parameters ---------- condition: array - when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). x1: array first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). x2: array From 640e6cdcd977fb40f62eff7bd527c535cd3f7fce Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 12 Dec 2024 06:10:14 -0800 Subject: [PATCH 524/551] feat: add complex dtype support for `mean` (#850) --- .../_draft/statistical_functions.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 347a97fff..92ffe60c5 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -177,7 +177,7 @@ def mean( Parameters ---------- x: array - input array. Should have a real-valued floating-point data type. + input array. Should have a floating-point data type. axis: Optional[Union[int, Tuple[int, ...]]] axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. keepdims: bool @@ -189,17 +189,26 @@ def mean( if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. .. note:: - While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. Notes ----- **Special Cases** - Let ``N`` equal the number of elements over which to compute the arithmetic mean. + Let ``N`` equal the number of elements over which to compute the arithmetic mean. For real-valued operands, - If ``N`` is ``0``, the arithmetic mean is ``NaN``. - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). + + For complex floating-point operands, real-valued floating-point special cases should independently apply to the real and imaginary component operations involving real numbers. For example, let ``a = real(x_i)`` and ``b = imag(x_i)``, and + + - If ``N`` is ``0``, the arithmetic mean is ``NaN + NaN j``. + - If ``a`` is ``NaN``, the real component of the result is ``NaN``. + - Similarly, if ``b`` is ``NaN``, the imaginary component of the result is ``NaN``. + + .. note:: + Array libraries, such as NumPy, PyTorch, and JAX, currently deviate from this specification in their handling of components which are ``NaN`` when computing the arithmetic mean. In general, consumers of array libraries implementing this specification should use :func:`~array_api.isnan` to test whether the result of computing the arithmetic mean over an array have a complex floating-point data type is ``NaN``, rather than relying on ``NaN`` propagation of individual components. """ From 7757e67a93eecb5c0a085e65d04d9b127a37f6af Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 6 Jan 2025 10:29:49 -0800 Subject: [PATCH 525/551] feat: add support for scalars in `result_type` PR-URL: https://github.com/data-apis/array-api/pull/873 Closes: https://github.com/data-apis/array-api/issues/805 Reviewed-by: lucas.colley8@gmail.com --- .../_draft/data_type_functions.py | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index e12d349c6..f953f0596 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -209,20 +209,25 @@ def isdtype( """ -def result_type(*arrays_and_dtypes: Union[array, dtype]) -> dtype: +def result_type( + *arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] +) -> dtype: """ - Returns the dtype that results from applying the type promotion rules (see :ref:`type-promotion`) to the arguments. - - .. note:: - If provided mixed dtypes (e.g., integer and floating-point), the returned dtype will be implementation-specific. + Returns the dtype that results from applying type promotion rules (see :ref:`type-promotion`) to the arguments. Parameters ---------- - arrays_and_dtypes: Union[array, dtype] - an arbitrary number of input arrays and/or dtypes. + arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] + an arbitrary number of input arrays, scalars, and/or dtypes. Returns ------- out: dtype - the dtype resulting from an operation involving the input arrays and dtypes. + the dtype resulting from an operation involving the input arrays, scalars, and/or dtypes. + + Notes + ----- + + - At least one argument must be an array or a dtype. + - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and is implementation-dependent. """ From 456d186a5669e986e6dcd29fb5b495a235b86fd9 Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Thu, 9 Jan 2025 07:50:47 +0000 Subject: [PATCH 526/551] docs: clarify behavior when providing a zero-dimensional array to `take` PR-URL: https://github.com/data-apis/array-api/pull/876 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_draft/indexing_functions.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index a9b38b482..536317dbb 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -13,7 +13,7 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: Parameters ---------- x: array - input array. + input array. Should have one or more dimensions (axes). indices: array array indices. The array must be one-dimensional and have an integer data type. @@ -33,6 +33,8 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: Notes ----- + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + .. versionadded:: 2022.12 .. versionchanged:: 2023.12 From fd6f507ee2037a66a1a194ccb50fb4f2b1411ee4 Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 9 Jan 2025 00:32:35 -0800 Subject: [PATCH 527/551] fix: address default value regression for `axis` kwarg in `vecdot` PR-URL: https://github.com/data-apis/array-api/pull/880 Closes: https://github.com/data-apis/array-api/issues/804 Ref: https://github.com/data-apis/array-api/issues/355 Ref: https://github.com/data-apis/array-api/pull/358 Ref: https://github.com/data-apis/array-api/commit/cbbab62922ab7ddd4f31302c21f22d2db62d6f16 --- src/array_api_stubs/_2021_12/linalg.py | 2 +- src/array_api_stubs/_2022_12/linalg.py | 2 +- src/array_api_stubs/_2023_12/linalg.py | 2 +- src/array_api_stubs/_draft/linalg.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/array_api_stubs/_2021_12/linalg.py b/src/array_api_stubs/_2021_12/linalg.py index 4e4ba52b2..06aa0accd 100644 --- a/src/array_api_stubs/_2021_12/linalg.py +++ b/src/array_api_stubs/_2021_12/linalg.py @@ -474,7 +474,7 @@ def trace(x: array, /, *, offset: int = 0) -> array: """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """ Alias for :func:`~array_api.vecdot`. """ diff --git a/src/array_api_stubs/_2022_12/linalg.py b/src/array_api_stubs/_2022_12/linalg.py index b13a5bf01..beec652bc 100644 --- a/src/array_api_stubs/_2022_12/linalg.py +++ b/src/array_api_stubs/_2022_12/linalg.py @@ -755,7 +755,7 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """Alias for :func:`~array_api.vecdot`.""" diff --git a/src/array_api_stubs/_2023_12/linalg.py b/src/array_api_stubs/_2023_12/linalg.py index a1c9fe028..a43dc8dcf 100644 --- a/src/array_api_stubs/_2023_12/linalg.py +++ b/src/array_api_stubs/_2023_12/linalg.py @@ -781,7 +781,7 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """Alias for :func:`~array_api.vecdot`.""" diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index a1c9fe028..a43dc8dcf 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -781,7 +781,7 @@ def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> arr """ -def vecdot(x1: array, x2: array, /, *, axis: int = None) -> array: +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: """Alias for :func:`~array_api.vecdot`.""" From d12a5e31564ba3dd16d0a328feb67964c07da1e7 Mon Sep 17 00:00:00 2001 From: Tim Head Date: Thu, 9 Jan 2025 11:41:28 +0100 Subject: [PATCH 528/551] feat: add scalar support to `where` PR-URL: https://github.com/data-apis/array-api/pull/860 Ref: https://github.com/data-apis/array-api/issues/807 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Evgeni Burovski Reviewed-by: Lucas Colley --- .../API_specification/type_promotion.rst | 3 +++ .../_draft/searching_functions.py | 20 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/spec/draft/API_specification/type_promotion.rst b/spec/draft/API_specification/type_promotion.rst index 339b90e45..4b3791aca 100644 --- a/spec/draft/API_specification/type_promotion.rst +++ b/spec/draft/API_specification/type_promotion.rst @@ -120,6 +120,9 @@ Notes .. note:: Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. + +.. _mixing-scalars-and-arrays: + Mixing arrays with Python scalars ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 9e0053825..04d4fd818 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -168,7 +168,12 @@ def searchsorted( """ -def where(condition: array, x1: array, x2: array, /) -> array: +def where( + condition: array, + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: """ Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. @@ -176,13 +181,22 @@ def where(condition: array, x1: array, x2: array, /) -> array: ---------- condition: array when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). - x1: array + x1: Union[array, int, float, complex, bool] first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). - x2: array + x2: Union[array, int, float, complex, bool] second input array. Must be compatible with ``condition`` and ``x1`` (see :ref:`broadcasting`). Returns ------- out: array an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. + + Notes + ----- + + - At least one of ``x1`` and ``x2`` must be an array. + - If either ``x1`` or ``x2`` is a scalar value, the returned array must have a data type determined according to :ref:`mixing-scalars-and-arrays`. + + .. versionchanged:: 2024.12 + Added support for scalar arguments. """ From 532db5baeb7d47f28e6b0e3f0ede2e180bc0688f Mon Sep 17 00:00:00 2001 From: Athan Date: Thu, 9 Jan 2025 03:24:40 -0800 Subject: [PATCH 529/551] feat: add scalar support to element-wise functions PR-URL: https://github.com/data-apis/array-api/pull/862 Ref: https://github.com/data-apis/array-api/issues/807 Reviewed-by: Evgeni Burovski --- src/array_api_stubs/_draft/array_object.py | 179 ++++----- .../_draft/elementwise_functions.py | 361 +++++++++++------- 2 files changed, 300 insertions(+), 240 deletions(-) diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 3c6fa8763..6d55b1eee 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -148,7 +148,7 @@ def __abs__(self: array, /) -> array: Added complex data type support. """ - def __add__(self: array, other: Union[int, float, array], /) -> array: + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the sum for each element of an array instance with the respective element of the array ``other``. @@ -167,8 +167,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. .. versionchanged:: 2022.12 Added complex data type support. @@ -190,9 +189,10 @@ def __and__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. """ def __array_namespace__( @@ -494,7 +494,7 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: ONE_API = 14 """ - def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -502,7 +502,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -510,12 +510,11 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. """ def __float__(self: array, /) -> float: @@ -584,9 +583,6 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -599,12 +595,12 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __getitem__( @@ -645,9 +641,6 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -660,12 +653,12 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __index__(self: array, /) -> int: @@ -769,9 +762,6 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -784,12 +774,12 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -808,18 +798,16 @@ def __lshift__(self: array, other: Union[int, array], /) -> array: out: array an array containing the element-wise results. The returned array must have the same data type as ``self``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. """ def __lt__(self: array, other: Union[int, float, array], /) -> array: """ Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- self: array @@ -832,12 +820,12 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ def __matmul__(self: array, other: array, /) -> array: @@ -892,9 +880,6 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: """ Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - Parameters ---------- self: array @@ -907,12 +892,14 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: out: array an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. """ - def __mul__(self: array, other: Union[int, float, array], /) -> array: + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. @@ -923,7 +910,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -934,14 +921,13 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. .. versionchanged:: 2022.12 Added complex data type support. """ - def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -949,7 +935,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -957,15 +943,11 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). - Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. - - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. .. versionchanged:: 2022.12 Added complex data type support. @@ -1017,9 +999,10 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. """ def __pos__(self: array, /) -> array: @@ -1046,20 +1029,15 @@ def __pos__(self: array, /) -> array: Added complex data type support. """ - def __pow__(self: array, other: Union[int, float, array], /) -> array: + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. - .. note:: - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - Parameters ---------- self: array array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1070,8 +1048,9 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. .. versionchanged:: 2022.12 Added complex data type support. @@ -1093,9 +1072,10 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: out: array an array containing the element-wise results. The returned array must have the same data type as ``self``. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. """ def __setitem__( @@ -1103,7 +1083,7 @@ def __setitem__( key: Union[ int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array ], - value: Union[int, float, bool, array], + value: Union[int, float, complex, bool, array], /, ) -> None: """ @@ -1117,30 +1097,26 @@ def __setitem__( array instance. key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] index key. - value: Union[int, float, bool, array] + value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). + Notes + ----- - .. note:: - - Setting array values must not affect the data type of ``self``. - - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). - - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + - Setting array values must not affect the data type of ``self``. + - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``complex``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. """ - def __sub__(self: array, other: Union[int, float, array], /) -> array: + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the difference for each element of an array instance with the respective element of the array ``other``. - The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). - Parameters ---------- self: array array instance (minuend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1151,27 +1127,22 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + - The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). .. versionchanged:: 2022.12 Added complex data type support. """ - def __truediv__(self: array, other: Union[int, float, array], /) -> array: + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. - .. note:: - If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - - Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. - Parameters ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1182,8 +1153,11 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: Notes ----- - .. note:: - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + - If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. .. versionchanged:: 2022.12 Added complex data type support. @@ -1205,9 +1179,10 @@ def __xor__(self: array, other: Union[int, bool, array], /) -> array: out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + Notes + ----- - .. note:: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. """ def to_device( diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 156715200..fa9390a01 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -272,15 +272,17 @@ def acosh(x: array, /) -> array: """ -def add(x1: array, x2: array, /) -> array: +def add( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: """ Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -291,6 +293,8 @@ def add(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, @@ -514,7 +518,7 @@ def atan(x: array, /) -> array: """ -def atan2(x1: array, x2: array, /) -> array: +def atan2(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. @@ -527,9 +531,9 @@ def atan2(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int, float] input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -540,6 +544,8 @@ def atan2(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For floating-point operands, @@ -639,39 +645,49 @@ def atanh(x: array, /) -> array: """ -def bitwise_and(x1: array, x2: array, /) -> array: +def bitwise_and(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: """ Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, bool] first input array. Should have an integer or boolean data type. - x2: array + x2: Union[array, int, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def bitwise_left_shift(x1: array, x2: array, /) -> array: +def bitwise_left_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. Parameters ---------- - x1: array + x1: Union[array, int] first input array. Should have an integer data type. - x2: array + x2: Union[array, int] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ @@ -691,25 +707,30 @@ def bitwise_invert(x: array, /) -> array: """ -def bitwise_or(x1: array, x2: array, /) -> array: +def bitwise_or(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: """ Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, bool] first input array. Should have an integer or boolean data type. - x2: array + x2: Union[array, int, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def bitwise_right_shift(x1: array, x2: array, /) -> array: +def bitwise_right_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: """ Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. @@ -718,33 +739,43 @@ def bitwise_right_shift(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int] first input array. Should have an integer data type. - x2: array + x2: Union[array, int] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def bitwise_xor(x1: array, x2: array, /) -> array: +def bitwise_xor(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: """ Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, bool] first input array. Should have an integer or boolean data type. - x2: array + x2: Union[array, int, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ @@ -793,9 +824,9 @@ def clip( x: array input array. Should have a real-valued data type. min: Optional[Union[int, float, array]] - lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. max: Optional[Union[int, float, array]] - upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. Returns ------- @@ -852,15 +883,15 @@ def conj(x: array, /) -> array: """ -def copysign(x1: array, x2: array, /) -> array: +def copysign(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. Parameters ---------- - x1: array + x1: Union[array, int, float] input array containing magnitudes. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -871,6 +902,8 @@ def copysign(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, @@ -1003,20 +1036,17 @@ def cosh(x: array, /) -> array: """ -def divide(x1: array, x2: array, /) -> array: +def divide( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: r""" Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. - - Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. - Parameters ---------- - x1: array + x1: Union[array, int, float, complex] dividend input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1027,6 +1057,12 @@ def divide(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + + - If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + **Special cases** For real-valued floating-point operands, @@ -1086,15 +1122,19 @@ def divide(x1: array, x2: array, /) -> array: """ -def equal(x1: array, x2: array, /) -> array: +def equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: r""" Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float, complex, bool] first input array. May have any data type. - x2: array + x2: Union[array, int, float, complex, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. Returns @@ -1105,6 +1145,8 @@ def equal(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special Cases** For real-valued floating-point operands, @@ -1279,18 +1321,17 @@ def floor(x: array, /) -> array: """ -def floor_divide(x1: array, x2: array, /) -> array: +def floor_divide( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: r""" Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. - .. note:: - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - Parameters ---------- - x1: array + x1: Union[array, int, float] dividend input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1301,6 +1342,9 @@ def floor_divide(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + **Special cases** .. note:: @@ -1339,18 +1383,15 @@ def floor_divide(x1: array, x2: array, /) -> array: """ -def greater(x1: array, x2: array, /) -> array: +def greater(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1358,24 +1399,27 @@ def greater(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ -def greater_equal(x1: array, x2: array, /) -> array: +def greater_equal( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: """ Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1383,12 +1427,16 @@ def greater_equal(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ -def hypot(x1: array, x2: array, /) -> array: +def hypot(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1397,9 +1445,9 @@ def hypot(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -1410,7 +1458,8 @@ def hypot(x1: array, x2: array, /) -> array: Notes ----- - The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + - At least one of ``x1`` or ``x2`` must be an array. + - The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. **Special Cases** @@ -1562,18 +1611,15 @@ def isnan(x: array, /) -> array: """ -def less(x1: array, x2: array, /) -> array: +def less(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1581,23 +1627,24 @@ def less(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ -def less_equal(x1: array, x2: array, /) -> array: +def less_equal(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - .. note:: - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). - Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1605,8 +1652,12 @@ def less_equal(x1: array, x2: array, /) -> array: out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. - .. note:: - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). """ @@ -1818,15 +1869,15 @@ def log10(x: array, /) -> array: """ -def logaddexp(x1: array, x2: array, /) -> array: +def logaddexp(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. Returns @@ -1837,6 +1888,8 @@ def logaddexp(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For floating-point operands, @@ -1847,7 +1900,7 @@ def logaddexp(x1: array, x2: array, /) -> array: """ -def logical_and(x1: array, x2: array, /) -> array: +def logical_and(x1: Union[array, bool], x2: Union[array, bool], /) -> array: """ Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1856,15 +1909,20 @@ def logical_and(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, bool] first input array. Should have a boolean data type. - x2: array + x2: Union[array, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type of `bool`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ @@ -1887,7 +1945,7 @@ def logical_not(x: array, /) -> array: """ -def logical_or(x1: array, x2: array, /) -> array: +def logical_or(x1: Union[array, bool], x2: Union[array, bool], /) -> array: """ Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1896,19 +1954,24 @@ def logical_or(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, bool] first input array. Should have a boolean data type. - x2: array + x2: Union[array, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def logical_xor(x1: array, x2: array, /) -> array: +def logical_xor(x1: Union[array, bool], x2: Union[array, bool], /) -> array: """ Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -1917,27 +1980,32 @@ def logical_xor(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, bool] first input array. Should have a boolean data type. - x2: array + x2: Union[array, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. Returns ------- out: array an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. """ -def maximum(x1: array, x2: array, /) -> array: +def maximum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1948,9 +2016,9 @@ def maximum(x1: array, x2: array, /) -> array: Notes ----- - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. - - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). **Special Cases** @@ -1962,15 +2030,15 @@ def maximum(x1: array, x2: array, /) -> array: """ -def minimum(x1: array, x2: array, /) -> array: +def minimum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: r""" Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -1981,9 +2049,9 @@ def minimum(x1: array, x2: array, /) -> array: Notes ----- - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. - - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). **Special Cases** @@ -1995,7 +2063,9 @@ def minimum(x1: array, x2: array, /) -> array: """ -def multiply(x1: array, x2: array, /) -> array: +def multiply( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: r""" Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. @@ -2004,9 +2074,9 @@ def multiply(x1: array, x2: array, /) -> array: Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -2017,6 +2087,8 @@ def multiply(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, @@ -2091,15 +2163,15 @@ def negative(x: array, /) -> array: """ -def nextafter(x1: array, x2: array, /) -> array: +def nextafter(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Returns the next representable floating-point value for each element ``x1_i`` of the input array ``x1`` in the direction of the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float] first input array. Should have a real-valued floating-point data type. - x2: array + x2: Union[array, int, float] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have the same data type as ``x1``. Returns @@ -2110,6 +2182,8 @@ def nextafter(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special cases** For real-valued floating-point operands, @@ -2120,15 +2194,19 @@ def nextafter(x1: array, x2: array, /) -> array: """ -def not_equal(x1: array, x2: array, /) -> array: +def not_equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: """ Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. Parameters ---------- - x1: array + x1: Union[array, int, float, complex, bool] first input array. May have any data type. - x2: array + x2: Union[array, int, float, complex, bool] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Returns @@ -2139,6 +2217,8 @@ def not_equal(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + **Special Cases** For real-valued floating-point operands, @@ -2187,27 +2267,17 @@ def positive(x: array, /) -> array: """ -def pow(x1: array, x2: array, /) -> array: +def pow( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. - .. note:: - If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. - - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). - - .. note:: - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. - - The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). - - *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). - Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array whose elements correspond to the exponentiation base. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -2218,6 +2288,18 @@ def pow(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + + - If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + **Special cases** For real-valued floating-point operands, @@ -2301,21 +2383,18 @@ def reciprocal(x: array, /) -> array: """ -def remainder(x1: array, x2: array, /) -> array: +def remainder(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: """ Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. .. note:: This function is equivalent to the Python modulus operator ``x1_i % x2_i``. - .. note:: - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. - Parameters ---------- - x1: array + x1: Union[array, int, float] dividend input array. Should have a real-valued data type. - x2: array + x2: Union[array, int, float] divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Returns @@ -2326,6 +2405,9 @@ def remainder(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + **Special cases** .. note:: @@ -2681,17 +2763,17 @@ def sqrt(x: array, /) -> array: """ -def subtract(x1: array, x2: array, /) -> array: +def subtract( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: """ Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. - The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). - Parameters ---------- - x1: array + x1: Union[array, int, float, complex] first input array. Should have a numeric data type. - x2: array + x2: Union[array, int, float, complex] second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -2702,6 +2784,9 @@ def subtract(x1: array, x2: array, /) -> array: Notes ----- + - At least one of ``x1`` or ``x2`` must be an array. + - The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + .. versionchanged:: 2022.12 Added complex data type support. """ From 52bbfebe4f5f4795063bdbcc4abd48a413bb9a3f Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 20 Jan 2025 01:26:23 -0800 Subject: [PATCH 530/551] docs: clarify type promotion behavior in `diff` PR-URL: https://github.com/data-apis/array-api/pull/881 Closes: https://github.com/data-apis/array-api/issues/852 Reviewed-by: Ralf Gommers --- src/array_api_stubs/_draft/utility_functions.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index cdbe4a0f8..7a234efbb 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -125,4 +125,5 @@ def diff( ----- - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). + - If a conforming implementation chooses to support ``prepend`` and ``append`` arrays which have a different data type than ``x``, behavior is unspecified and thus implementation-defined. Implementations may choose to type promote (:ref:`type-promotion`), cast ``prepend`` and/or ``append`` to the same data type as ``x``, or raise an exception. """ From 73e722861650872733e7d89e5d297c24989920f1 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:12:34 -0800 Subject: [PATCH 531/551] feat: add `dtype` kwarg support to `fftfreq` and `rfftfreq` PR-URL: https://github.com/data-apis/array-api/pull/885 Closes: https://github.com/data-apis/array-api/issues/717 Reviewed-by: Evgeni Burovski --- src/array_api_stubs/_draft/fft.py | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 7a4538ccb..3d1f4d9c7 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -15,7 +15,7 @@ "ifftshift", ] -from ._types import Tuple, Union, Sequence, array, Optional, Literal, device +from ._types import Tuple, Union, Sequence, array, Optional, Literal, dtype, device def fft( @@ -551,7 +551,14 @@ def ihfft( """ -def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: +def fftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Computes the discrete Fourier transform sample frequencies. @@ -568,13 +575,15 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar window length. d: float sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. Returns ------- out: array - an array of shape ``(n,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + an array of shape ``(n,)`` containing the sample frequencies. Notes ----- @@ -586,7 +595,14 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> ar """ -def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> array: +def rfftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: """ Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). @@ -605,13 +621,15 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[device] = None) -> a window length. d: float sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. device: Optional[device] device on which to place the created array. Default: ``None``. Returns ------- out: array - an array of shape ``(n//2+1,)`` containing the sample frequencies. The returned array must have the default real-valued floating-point data type. + an array of shape ``(n//2+1,)`` containing the sample frequencies. Notes ----- From b0aacd9e51085b31a5a2f48778e5a3ae5eef7069 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:19:29 -0800 Subject: [PATCH 532/551] fix: resolve conflicting exception guidance in `__dlpack__` PR-URL: https://github.com/data-apis/array-api/pull/887 Closes: https://github.com/data-apis/array-api/issues/831 --- src/array_api_stubs/_2023_12/array_object.py | 2 +- src/array_api_stubs/_draft/array_object.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index 5c0b10dd9..f5cc9bcee 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -364,7 +364,7 @@ def __dlpack__( ``__dlpack__`` to return a capsule referencing an array whose underlying memory is accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). If a copy must be made to enable this support but ``copy`` is set to ``False``, the - function must raise ``ValueError``. + function must raise ``BufferError``. Other device kinds will be considered for standardization in a future version of this API standard. diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 6d55b1eee..ee4c2a0e3 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -364,7 +364,7 @@ def __dlpack__( ``__dlpack__`` to return a capsule referencing an array whose underlying memory is accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). If a copy must be made to enable this support but ``copy`` is set to ``False``, the - function must raise ``ValueError``. + function must raise ``BufferError``. Other device kinds will be considered for standardization in a future version of this API standard. From 7adeae8b6c4e7820e69b7325032a6d3d9a1af3b3 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:31:51 -0800 Subject: [PATCH 533/551] feat!: apply type promotion rules according to the device context PR-URL: https://github.com/data-apis/array-api/pull/889 Closes: https://github.com/data-apis/array-api/issues/672 BREAKING CHANGE: `can_cast` and `result_type` must account for device context Previously, the specification only required that conforming libraries consider the type promotion graph as defined in the specification. However, that resulted in situations where `can_cast` and `result_type` diverged from actual behavior due to device limitations. This commit requires conforming implementations to consider the device context when applying type promotion rules. --- src/array_api_stubs/_draft/data_type_functions.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index f953f0596..db793c16e 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -65,7 +65,7 @@ def astype( def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: """ - Determines if one data type can be cast to another data type according :ref:`type-promotion` rules. + Determines if one data type can be cast to another data type according to type promotion rules (see :ref:`type-promotion`). Parameters ---------- @@ -77,7 +77,13 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: Returns ------- out: bool - ``True`` if the cast can occur according to :ref:`type-promotion` rules; otherwise, ``False``. + ``True`` if the cast can occur according to type promotion rules (see :ref:`type-promotion`); otherwise, ``False``. + + Notes + ----- + + - When ``from_`` is a data type, the function must determine whether the data type can be cast to another data type according to the complete type promotion rules (see :ref:`type-promotion`) described in this specification, irrespective of whether a conforming array library supports devices which do not have full data type support. + - When ``from_`` is an array, the function must determine whether the data type of the array can be cast to the desired data type according to the type promotion graph of the array device. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the output of ``can_cast(array, dtype)`` may differ from ``can_cast(array.dtype, dtype)``. """ @@ -229,5 +235,7 @@ def result_type( ----- - At least one argument must be an array or a dtype. - - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and is implementation-dependent. + - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and thus implementation-dependent. + - If at least one argument is an array, the function must determine the resulting dtype according to the type promotion graph of the array device which is shared among all array arguments. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the returned dtype may differ from that determined from the complete type promotion graph defined in this specification (see :ref:`type-promotion`). + - If two or more arguments are arrays belonging to different devices, behavior is unspecified and thus implementation-dependent. Conforming implementations may choose to ignore device attributes, raise an exception, or some other behavior. """ From 4f26831f8bf38f042692f75973abef31088cbe04 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 18:35:07 -0800 Subject: [PATCH 534/551] fix: clarify broadcast behavior in `broadcast_to` PR-URL: https://github.com/data-apis/array-api/pull/888 Closes: https://github.com/data-apis/array-api/issues/823 --- src/array_api_stubs/_draft/manipulation_functions.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 131b81eb3..c09f2643b 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -42,14 +42,14 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: Parameters ---------- x: array - array to broadcast. + array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. shape: Tuple[int, ...] - array shape. Must be compatible with ``x`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + array shape. Returns ------- out: array - an array having a specified shape. Must have the same data type as ``x``. + an array having the specified shape. Must have the same data type as ``x``. """ From 071780c7480fe05588afc768df3c3d15c5fc550e Mon Sep 17 00:00:00 2001 From: Evgeni Burovski Date: Thu, 6 Feb 2025 04:00:35 +0100 Subject: [PATCH 535/551] feat: add support for real-valued arrays in `real` and `conj` PR-URL: https://github.com/data-apis/array-api/pull/884 Closes: https://github.com/data-apis/array-api/issues/824 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Ralf Gommers --- src/array_api_stubs/_draft/elementwise_functions.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index fa9390a01..119881adc 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -869,7 +869,7 @@ def conj(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex floating-point data type. + input array. Must have a numeric data type. Returns ------- @@ -879,6 +879,8 @@ def conj(x: array, /) -> array: Notes ----- + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + .. versionadded:: 2022.12 """ @@ -2346,7 +2348,7 @@ def real(x: array, /) -> array: Parameters ---------- x: array - input array. Should have a complex floating-point data type. + input array. Must have a numeric data type. Returns ------- @@ -2356,6 +2358,8 @@ def real(x: array, /) -> array: Notes ----- + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + .. versionadded:: 2022.12 """ From df8081cafb31a7e09665180e3454df4b61356b87 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 21:44:50 -0800 Subject: [PATCH 536/551] docs: clarify support for negative indices in `take` and `take_along_axis` PR-URL: https://github.com/data-apis/array-api/pull/894 Reviewed-by: Matt Haberland --- .../_draft/indexing_functions.py | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 536317dbb..8be7cc00e 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -7,21 +7,14 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: """ Returns elements of an array along an axis. - .. note:: - 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. Should have one or more dimensions (axes). indices: array - array indices. The array must be one-dimensional and have an integer data type. - - .. note:: - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - + array indices. The array must be one-dimensional and have an integer data type. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). axis: Optional[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. + 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 (where ``-1`` refers to 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. @@ -33,6 +26,8 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: Notes ----- + - 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. + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. .. versionadded:: 2022.12 @@ -51,16 +46,17 @@ def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: x: array input array. Must be compatible with ``indices``, except for the axis (dimension) specified by ``axis`` (see :ref:`broadcasting`). indices: array - array indices. Must have the same rank (i.e., number of dimensions) as ``x``. - - .. note:: - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. - + array indices. Must have the same rank (i.e., number of dimensions) as ``x``. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). axis: int - axis along 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. Default: ``-1``. + axis along 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 (where ``-1`` refers to the last dimension). Default: ``-1``. Returns ------- out: array an array having the same data type as ``x``. Must have the same rank (i.e., number of dimensions) as ``x`` and must have a shape determined according to :ref:`broadcasting`, except for the axis (dimension) specified by ``axis`` whose size must equal the size of the corresponding axis (dimension) in ``indices``. + + Notes + ----- + + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. """ From 4dccde523af32b3346f90e5dd2b2f90d26319a34 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 5 Feb 2025 21:48:24 -0800 Subject: [PATCH 537/551] docs: clarify that `sqrt` must be correctly rounded in accordance with IEEE 754 PR-URL: https://github.com/data-apis/array-api/pull/882 Closes: https://github.com/data-apis/array-api/issues/826 Closes: https://github.com/data-apis/array-api/issues/830 Reviewed-by: Leo Fang --- spec/draft/design_topics/accuracy.rst | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/spec/draft/design_topics/accuracy.rst b/spec/draft/design_topics/accuracy.rst index 61a2c49aa..9d82dbb1f 100644 --- a/spec/draft/design_topics/accuracy.rst +++ b/spec/draft/design_topics/accuracy.rst @@ -23,11 +23,20 @@ including the corresponding element-wise array APIs defined in this standard - multiply - divide -for floating-point operands must return the nearest representable value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). + +IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, conforming implementations may vary in their support for subnormal numbers. Mathematical Functions ---------------------- +The results of the following functions + +- reciprocal +- sqrt + +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. + This specification does **not** precisely define the behavior of the following functions - acos @@ -41,10 +50,12 @@ This specification does **not** precisely define the behavior of the following f - cosh - exp - expm1 +- hypot - log - log1p - log2 - log10 +- logaddexp - pow - sin - sinh @@ -75,3 +86,8 @@ Linear Algebra -------------- This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +Operations Involving Complex Numbers +------------------------------------ + +This specification does not specify accuracy requirements for arithmetic or functional operations involving complex-valued floating-point operands; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. From c7476ba49e7a5ace85e6bb36962a0ee63c7c1963 Mon Sep 17 00:00:00 2001 From: Evgeni Burovski Date: Thu, 6 Feb 2025 09:27:15 +0100 Subject: [PATCH 538/551] feat: define complex scalar fp array PR-URL: https://github.com/data-apis/array-api/pull/871 Closes: https://github.com/data-apis/array-api/issues/841 Ref: https://github.com/data-apis/array-api/issues/478 Co-authored-by: Athan Reines Reviewed-by: Athan Reines Reviewed-by: Lucas Colley --- .../API_specification/type_promotion.rst | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/spec/draft/API_specification/type_promotion.rst b/spec/draft/API_specification/type_promotion.rst index 4b3791aca..7a82c763b 100644 --- a/spec/draft/API_specification/type_promotion.rst +++ b/spec/draft/API_specification/type_promotion.rst @@ -110,7 +110,6 @@ where - **c16**: double-precision complex floating-point number (i.e., ``complex128``) composed of two double-precision (64-bit) floating-point numbers - Notes ~~~~~ @@ -140,12 +139,25 @@ where ```` is a built-in operator (including in-place operators, but excludi Provided the above requirements are met, the expected behavior is equivalent to: -1. Convert the scalar to zero-dimensional array with the same data type as that of the array used in the expression. +1. Convert the scalar to a zero-dimensional array with the same data type as that of the array used in the expression. 2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). -.. note:: - Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. +Additionally, using Python ``complex`` scalars together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with a promoted array data type: + +- a Python ``complex`` for real-valued floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to a zero-dimensional array with a complex floating-point array data type having the same precision as that of the array operand used in the expression (e.g., if an array has a ``float32`` data type, the scalar must be converted to a zero-dimensional array having a ``complex64`` data type; if an array has a ``float64`` data type, the scalar must be converted to a zero-dimensional array have a ``complex128`` data type). +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +Behavior is not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. - Similarly, behavior is not specified when mixing a Python ``complex`` and an array with a real-valued data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. +Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. - Behavior is also not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. +Behavior is not specified when mixing a Python ``complex`` and an array with an integer data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. From f73baff3a59ce9ab84ff3fea0cf30a8af69a3d0d Mon Sep 17 00:00:00 2001 From: Aaron Meurer Date: Thu, 6 Feb 2025 02:29:00 -0700 Subject: [PATCH 539/551] docs: clarify that `clip` behavior is undefined when `min` or `max` is outside the bounds of `x` PR-URL: https://github.com/data-apis/array-api/pull/814 Ref: https://github.com/numpy/numpy/issues/24976 Co-authored-by: Athan Reines Reviewed-by: Athan Reines --- src/array_api_stubs/_2023_12/elementwise_functions.py | 1 + src/array_api_stubs/_draft/elementwise_functions.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index 251a770d6..f44838f63 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -805,6 +805,7 @@ def clip( - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. **Special cases** diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 119881adc..40775d6a3 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -838,6 +838,7 @@ def clip( - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. **Special cases** From 407a8aebced500b1fc0e38132a645e0142d51bb1 Mon Sep 17 00:00:00 2001 From: Athan Date: Sun, 16 Feb 2025 22:53:07 -0800 Subject: [PATCH 540/551] fix: resolve typo in `broadcast_to` to require an exception PR-URL: https://github.com/data-apis/array-api/pull/897 Ref: https://github.com/data-apis/array-api/pull/888/files#r1944366064 --- src/array_api_stubs/_draft/manipulation_functions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index c09f2643b..7e94cbc27 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -42,7 +42,7 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: Parameters ---------- x: array - array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function should raise an exception. + array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function must raise an exception. shape: Tuple[int, ...] array shape. From cfa91d3ef9e6faf711f653abb09b8a73de64ceb6 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Feb 2025 01:57:40 -0800 Subject: [PATCH 541/551] docs: clarify the expected results for in-place operations for immutable array libraries PR-URL: https://github.com/data-apis/array-api/pull/895 Closes: https://github.com/data-apis/array-api/issues/828 Reviewed-by: Sebastian Berg --- .../API_specification/array_object.rst | 2 +- spec/draft/API_specification/array_object.rst | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/spec/2023.12/API_specification/array_object.rst b/spec/2023.12/API_specification/array_object.rst index f8a586ade..6a41d4016 100644 --- a/spec/2023.12/API_specification/array_object.rst +++ b/spec/2023.12/API_specification/array_object.rst @@ -87,7 +87,7 @@ A conforming implementation of the array API standard must provide and support a - `operator.matmul(x1, x2) `_ - `operator.__matmul__(x1, x2) `_ -The matmul ``@`` operator should be defined for arrays having real-valued data types. +The matmul ``@`` operator should be defined for arrays having numeric data types. Bitwise Operators ~~~~~~~~~~~~~~~~~ diff --git a/spec/draft/API_specification/array_object.rst b/spec/draft/API_specification/array_object.rst index f8a586ade..e3c7e8ae6 100644 --- a/spec/draft/API_specification/array_object.rst +++ b/spec/draft/API_specification/array_object.rst @@ -87,7 +87,7 @@ A conforming implementation of the array API standard must provide and support a - `operator.matmul(x1, x2) `_ - `operator.__matmul__(x1, x2) `_ -The matmul ``@`` operator should be defined for arrays having real-valued data types. +The matmul ``@`` operator should be defined for arrays having numeric data types. Bitwise Operators ~~~~~~~~~~~~~~~~~ @@ -169,14 +169,28 @@ For backward compatibility, conforming implementations may support complex numbe In-place Operators ~~~~~~~~~~~~~~~~~~ -A conforming implementation of the array API standard must provide and support an array object supporting the following in-place Python operators. +.. note:: + In-place operations must be supported as discussed in :ref:`copyview-mutability`. + +A conforming implementation of the array API standard must provide and support an array object supporting the following "in-place" Python operators. + +.. note:: + This specification refers to the following operators as "in-place" as that is what these operators are called in `Python `. However, conforming array libraries which do not support array mutation may choose to not explicitly implement in-place Python operators. When a library does not implement a method corresponding to an in-place Python operator, Python falls back to the equivalent method for the corresponding binary arithmetic operation. An in-place operation must not change the data type or shape of the in-place array as a result of :ref:`type-promotion` or :ref:`broadcasting`. -An in-place operation must have the same behavior (including special cases) as its respective binary (i.e., two operand, non-assignment) operation. For example, after in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1 = x1 + x2``. +Let ``x1 += x2`` be a representative in-place operation. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands ``x1`` and ``x2``, the resulting data type is equal to the data type of the array on the left-hand side of the operation (i.e., ``x1``), then an in-place operation must have the same behavior (including special cases) as the respective binary (i.e., two operand, non-assignment) operation. In this case, for the in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1[...] = x1 + x2``. + +If, however, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of the array on the left-hand side of the operation, then a conforming implementation may return results which differ from the respective binary operation due to casting behavior and selection of the operation's intermediate precision. The choice of casting behavior and intermediate precision is unspecified and thus implementation-defined. .. note:: - In-place operators must be supported as discussed in :ref:`copyview-mutability`. + Let ``x1`` be the operand on the left-hand side and ``x2`` be the operand on the right-hand side of an in-place operation. Consumers of the array API standard are advised of the following considerations when using in-place operations: + + 1. In-place operations do not guarantee in-place mutation. A conforming library may or may not support in-place mutation. + 2. If, after applying broadcasting (see :ref:`broadcasting`) to in-place operands, the resulting shape is not equal to the shape of ``x1``, in-place operators may raise an exception. + 3. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of ``x1``, the resulting data type may not equal the data type of ``x1`` and the operation's intermediate precision may be that of ``x1``, even if the promoted data type between ``x1`` and ``x2`` would have higher precision. + + In general, for in-place operations, consumers of the array API standard are advised to ensure operands have the same data type and broadcast to the shape of the operand on the left-hand side of the operation in order to maximize portability. Arithmetic Operators """""""""""""""""""" From 0a425d19717802d3762b6beb472cdd3d8fb5e432 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Feb 2025 02:03:43 -0800 Subject: [PATCH 542/551] docs: clarify `clip` behavior when arguments have different data types PR-URL: https://github.com/data-apis/array-api/pull/896 Closes: https://github.com/data-apis/array-api/pull/811 Ref: https://github.com/data-apis/array-api/pull/814#issuecomment-2428088370 Ref: https://github.com/data-apis/array-api/issues/807 Reviewed-by: Ralf Gommers --- src/array_api_stubs/_2023_12/elementwise_functions.py | 4 ++-- src/array_api_stubs/_draft/elementwise_functions.py | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/array_api_stubs/_2023_12/elementwise_functions.py b/src/array_api_stubs/_2023_12/elementwise_functions.py index f44838f63..2972fa623 100644 --- a/src/array_api_stubs/_2023_12/elementwise_functions.py +++ b/src/array_api_stubs/_2023_12/elementwise_functions.py @@ -791,9 +791,9 @@ def clip( x: array input array. Should have a real-valued data type. min: Optional[Union[int, float, array]] - lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` and ``max`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. max: Optional[Union[int, float, array]] - upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` and ``min`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. Returns ------- diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index 40775d6a3..a35c04db5 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -824,22 +824,24 @@ def clip( x: array input array. Should have a real-valued data type. min: Optional[Union[int, float, array]] - lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` and ``max`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. max: Optional[Union[int, float, array]] - upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` (see :ref:`broadcasting`). Should have a real-valued data type. Default: ``None``. + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` and ``min`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. Returns ------- out: array - an array containing element-wise results. The returned array must have the same data type as ``x``. + an array containing element-wise results. The returned array should have the same data type as ``x``. Notes ----- + - This function is conceptually equivalent to ``maximum(minimum(x, max), min)`` when ``x``, ``min``, and ``max`` have the same data type. - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - For scalar ``min`` and/or ``max``, the scalar values should follow type promotion rules for operations involving arrays and scalar operands (see :ref:`type-promotion`). Hence, if ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. - - If ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + - If either ``min`` or ``max`` is an array having a different data type than ``x``, behavior is unspecified and thus implementation-dependent. **Special cases** From 287b83454a2908b4359dd0ac472cd561a21ee4f6 Mon Sep 17 00:00:00 2001 From: Athan Date: Mon, 17 Feb 2025 02:23:13 -0800 Subject: [PATCH 543/551] fix: address incorrect boundary conditions in `searchsorted` PR-URL: https://github.com/data-apis/array-api/pull/898 Closes: https://github.com/data-apis/array-api/issues/861 Reviewed-by: Matt Haberland Co-authored-by: Matt Haberland --- .../_2023_12/searching_functions.py | 15 ++++++--------- src/array_api_stubs/_draft/searching_functions.py | 15 ++++++--------- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py index 9d64fe6da..c854a1d98 100644 --- a/src/array_api_stubs/_2023_12/searching_functions.py +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -107,17 +107,14 @@ def searchsorted( side: Literal['left', 'right'] argument controlling which index is returned if a value lands exactly on an edge. - Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + Let ``v`` be an element of ``x2`` given by ``v = x2[j]``, where ``j`` refers to a valid index (see :ref:`indexing`). - If ``side == 'left'``, then + - If ``v`` is less than all elements in ``x1``, then ``out[j]`` must be ``0``. + - If ``v`` is greater than all elements in ``x1``, then ``out[j]`` must be ``M``, where ``M`` is the number of elements in ``x1``. + - Otherwise, each returned index ``i = out[j]`` must satisfy an index condition: - - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``0``. - - Otherwise, if ``side == 'right'``, then - - - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + - If ``side == 'left'``, then ``x1[i-1] < v <= x1[i]``. + - If ``side == 'right'``, then ``x1[i-1] <= v < x1[i]``. Default: ``'left'``. sorter: Optional[array] diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index 04d4fd818..d8676b68b 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -136,17 +136,14 @@ def searchsorted( side: Literal['left', 'right'] argument controlling which index is returned if a value lands exactly on an edge. - Let ``x`` be an array of rank ``N`` where ``v`` is an individual element given by ``v = x2[n,m,...,j]``. + Let ``v`` be an element of ``x2`` given by ``v = x2[j]``, where ``j`` refers to a valid index (see :ref:`indexing`). - If ``side == 'left'``, then + - If ``v`` is less than all elements in ``x1``, then ``out[j]`` must be ``0``. + - If ``v`` is greater than all elements in ``x1``, then ``out[j]`` must be ``M``, where ``M`` is the number of elements in ``x1``. + - Otherwise, each returned index ``i = out[j]`` must satisfy an index condition: - - each returned index ``i`` must satisfy the index condition ``x1[i-1] < v <= x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``0``. - - Otherwise, if ``side == 'right'``, then - - - each returned index ``i`` must satisfy the index condition ``x1[i-1] <= v < x1[i]``. - - if no index satisfies the index condition, then the returned index for that element must be ``N``, where ``N`` is the number of elements in ``x1``. + - If ``side == 'left'``, then ``x1[i-1] < v <= x1[i]``. + - If ``side == 'right'``, then ``x1[i-1] <= v < x1[i]``. Default: ``'left'``. sorter: Optional[array] From 04987212d5a5a17c36b81b6f9978e453a6651063 Mon Sep 17 00:00:00 2001 From: Athan Date: Fri, 21 Feb 2025 18:15:49 -0800 Subject: [PATCH 544/551] feat: add support for integer array indexing PR-URL: https://github.com/data-apis/array-api/pull/900 Closes: https://github.com/data-apis/array-api/issues/669 Co-authored-by: Evgeni Burovski Reviewed-by: Evgeni Burovski Reviewed-by: Stephan Hoyer Reviewed-by: Sebastian Berg Reviewed-by: Aaron Meurer --- spec/draft/API_specification/indexing.rst | 45 ++++++++++++++++++++++ src/array_api_stubs/_draft/array_object.py | 24 +++++++----- 2 files changed, 59 insertions(+), 10 deletions(-) diff --git a/spec/draft/API_specification/indexing.rst b/spec/draft/API_specification/indexing.rst index eb61c26d5..058003c51 100644 --- a/spec/draft/API_specification/indexing.rst +++ b/spec/draft/API_specification/indexing.rst @@ -7,6 +7,9 @@ Indexing A conforming implementation of the array API standard must adhere to the following conventions. + +.. _indexing-single-axis: + Single-axis Indexing -------------------- @@ -121,6 +124,9 @@ The behavior outside of these bounds is unspecified. .. note:: *Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip (consistent with Python* ``list`` *slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +.. _indexing-multi-axis: + Multi-axis Indexing ------------------- @@ -173,6 +179,45 @@ Multi-dimensional arrays must extend the concept of single-axis indexing to mult *Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to* ``0`` *, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* +Integer Array Indexing +---------------------- + +.. note:: + Integer array indexing, as described in this specification, is a reduced subset of "vectorized indexing" semantics, as implemented in libraries such as NumPy. In vectorized indexing, integers and integer arrays are broadcasted to integer arrays having a common shape before being "zipped" together to form a list of index coordinates. This form of indexing diverges from the multi-axis indexing semantics described above (see :ref:`indexing-multi-axis`) where each element of an indexing tuple comprised of integers and slices independently indexes a particular axis. This latter form of indexing is commonly referred to as "orthogonal indexing" and is the default form of indexing outside of Python in languages such as Julia and MATLAB. + +An array must support indexing by an indexing tuple which contains only integers and integer arrays according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S1``. Let ``T`` be a tuple ``(t1, t2, ..., tN)`` having length ``N``. Let ``tk`` be an individual element of ``T``. + +.. note:: + This specification does not currently address indexing tuples which combine slices and integer arrays. Behavior for such indexing tuples is left unspecified and thus implementation-defined. This may be revisited in a future revision of this standard. + +.. note:: + This specification does not currently address indexing tuples which include array-like elements, such as Python lists, tuples, and other sequences. Behavior when indexing an array using array-like elements is left unspecified and thus implementation-defined. + +- If ``tk`` is an integer array, ``tk`` should have the default array index data type (see :ref:`data-type-defaults`). + +.. note:: + Conforming implementations of this standard may support integer arrays having other integer data types; however, consumers of this standard should be aware that integer arrays having uncommon array index data types such as ``int8`` and ``uint8`` may not be widely supported as index arrays across conforming array libraries. To dynamically resolve the default array index data type, including for that of the current device context, use the inspection API ``default_dtypes()``. + +- Providing a zero-dimensional integer array ``tk`` containing an integer index must be equivalent to providing an integer index having the value ``int(tk)``. Conversely, each integer index ``tk`` must be equivalent to a zero-dimensional integer array containing the same value and be treated as such, including shape inference and broadcasting. Accordingly, if ``T`` consists of only integers and zero-dimensional integer arrays, the result must be equivalent to indexing multiple axes using integer indices. For example, if ``A`` is a two-dimensional array, ``T`` is the tuple ``(i, J)``, ``i`` is a valid integer index, and ``J`` is a zero-dimensional array containing a valid integer index ``j``, the result of ``A[T]`` must be equivalent to ``A[(i,j)]`` (see :ref:`indexing-multi-axis`). + +- If ``tk`` is an integer array, each element in ``tk`` must independently satisfy the rules stated above for indexing a single-axis with an integer index (see :ref:`indexing-single-axis`). + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- If ``tk`` is an integer array containing duplicate valid integer indices, the result must include the corresponding elements of ``A`` with the same duplication. + + .. + TODO: once setitem semantics are determined, insert the following note: Given the assignment operation ``x[T] = y[...]``, if ``T`` contains an integer array having duplicate indices, the order in which elements in ``y`` are assigned to the corresponding element(s) in ``x`` is unspecified and thus implementation-defined. + +- If ``T`` contains at least one non-zero-dimensional integer array, all elements of ``T`` must be broadcast against each other to determine a common shape ``S2 = (s1, s2, ..., sN)`` according to standard broadcasting rules (see :ref:`broadcasting`). If one or more elements in ``T`` are not broadcast-compatible with the others, an exception must be raised. + +- After broadcasting elements of ``T`` to a common shape ``S2``, the resulting tuple ``U = (u1, u2, ..., uN)`` must only contain integer arrays having shape ``S2`` (i.e., ``u1 = broadcast_to(t1, S2)``, ``u2 = broadcast_to(t2, S2)``, et cetera). + +- Each element in ``U`` must specify a multi-dimensional index ``v_i = (u1[i], u2[i], ..., uN[i])``, where ``i`` ranges over ``S2``. The result of ``A[U]`` must be constructed by gathering elements from ``A`` at each coordinate tuple ``v_i``. For example, let ``A`` have shape ``(4,4)`` and ``U`` contain integer arrays equivalent to ``([0,1], [2,3])``, with ``u1 = [0,1]`` and ``u2 = [2,3]``. The resulting coordinate tuples must be ``(0,2)`` and ``(1,3)``, respectively, and the resulting array must have shape ``(2,)`` and contain elements ``A[(0,2)]`` and ``A[(1,3)]``. + +- The result of ``A[U]`` must be an array having the broadcasted shape ``S2``. + Boolean Array Indexing ---------------------- diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index ee4c2a0e3..55ef60f07 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -610,7 +610,7 @@ def __getitem__( slice, ellipsis, None, - Tuple[Union[int, slice, ellipsis, None], ...], + Tuple[Union[int, slice, ellipsis, array, None], ...], array, ], /, @@ -618,13 +618,11 @@ def __getitem__( """ Returns ``self[key]``. - See :ref:`indexing` for details on supported indexing semantics. - Parameters ---------- self: array array instance. - key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, None], ...], array] + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, array, None], ...], array] index key. Returns @@ -632,8 +630,11 @@ def __getitem__( out: array an array containing the accessed value(s). The returned array must have the same data type as ``self``. - .. note:: - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + Notes + ----- + + - See :ref:`indexing` for details on supported indexing semantics. + - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. """ @@ -1081,7 +1082,7 @@ def __rshift__(self: array, other: Union[int, array], /) -> array: def __setitem__( self: array, key: Union[ - int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array ], value: Union[int, float, complex, bool, array], /, @@ -1089,13 +1090,11 @@ def __setitem__( """ Sets ``self[key]`` to ``value``. - See :ref:`indexing` for details on supported indexing semantics. - Parameters ---------- self: array array instance. - key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array] index key. value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). @@ -1103,6 +1102,11 @@ def __setitem__( Notes ----- + - See :ref:`indexing` for details on supported indexing semantics. + + .. note:: + Indexing semantics when ``key`` is an integer array or a tuple of integers and integer arrays is currently unspecified and thus implementation-defined. This will be revisited in a future revision of this standard. + - Setting array values must not affect the data type of ``self``. - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``complex``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. From 8b0852b4329360a0d8c3398e5ce9932f8fb30dff Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 01:38:24 -0800 Subject: [PATCH 545/551] fix: address typo in return type for `nonzero` PR-URL: https://github.com/data-apis/array-api/pull/904 --- src/array_api_stubs/_2021_12/searching_functions.py | 2 +- src/array_api_stubs/_2022_12/searching_functions.py | 2 +- src/array_api_stubs/_2023_12/searching_functions.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/array_api_stubs/_2021_12/searching_functions.py b/src/array_api_stubs/_2021_12/searching_functions.py index ca7d22420..eb615ffed 100644 --- a/src/array_api_stubs/_2021_12/searching_functions.py +++ b/src/array_api_stubs/_2021_12/searching_functions.py @@ -57,7 +57,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. """ diff --git a/src/array_api_stubs/_2022_12/searching_functions.py b/src/array_api_stubs/_2022_12/searching_functions.py index 2d2560502..303ceb8e1 100644 --- a/src/array_api_stubs/_2022_12/searching_functions.py +++ b/src/array_api_stubs/_2022_12/searching_functions.py @@ -73,7 +73,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. Notes diff --git a/src/array_api_stubs/_2023_12/searching_functions.py b/src/array_api_stubs/_2023_12/searching_functions.py index c854a1d98..4888f329e 100644 --- a/src/array_api_stubs/_2023_12/searching_functions.py +++ b/src/array_api_stubs/_2023_12/searching_functions.py @@ -76,7 +76,7 @@ def nonzero(x: array, /) -> Tuple[array, ...]: Returns ------- - out: Typle[array, ...] + out: Tuple[array, ...] a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. Notes From 6b8172ea0d154d07f65fd83f97dad9685405c5b6 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 01:49:37 -0800 Subject: [PATCH 546/551] fix: address missing `complex` type in applicable function signatures PR-URL: https://github.com/data-apis/array-api/pull/905 Ref: https://github.com/data-apis/array-api/pull/862 --- src/array_api_stubs/_2022_12/array_object.py | 38 ++++++++++---------- src/array_api_stubs/_2023_12/array_object.py | 35 +++++++++--------- src/array_api_stubs/_draft/array_object.py | 3 ++ 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/array_api_stubs/_2022_12/array_object.py b/src/array_api_stubs/_2022_12/array_object.py index 83abc9310..c5bfdf7a3 100644 --- a/src/array_api_stubs/_2022_12/array_object.py +++ b/src/array_api_stubs/_2022_12/array_object.py @@ -146,7 +146,7 @@ def __abs__(self: array, /) -> array: Added complex data type support. """ - def __add__(self: array, other: Union[int, float, array], /) -> array: + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the sum for each element of an array instance with the respective element of the array ``other``. @@ -154,7 +154,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (augend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -374,7 +374,7 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: ROCM = 10 """ - def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -382,7 +382,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -393,6 +393,9 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __float__(self: array, /) -> float: @@ -746,7 +749,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ - def __mul__(self: array, other: Union[int, float, array], /) -> array: + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. @@ -757,7 +760,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -775,7 +778,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -783,7 +786,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -852,9 +855,6 @@ def __or__(self: array, other: Union[int, bool, array], /) -> array: .. note:: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. - - .. versionchanged:: 2022.12 - Added complex data type support. """ def __pos__(self: array, /) -> array: @@ -876,7 +876,7 @@ def __pos__(self: array, /) -> array: Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. """ - def __pow__(self: array, other: Union[int, float, array], /) -> array: + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. @@ -889,7 +889,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -933,7 +933,7 @@ def __setitem__( key: Union[ int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array ], - value: Union[int, float, bool, array], + value: Union[int, float, complex, bool, array], /, ) -> None: """ @@ -947,7 +947,7 @@ def __setitem__( array instance. key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] index key. - value: Union[int, float, bool, array] + value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). @@ -960,7 +960,7 @@ def __setitem__( When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. """ - def __sub__(self: array, other: Union[int, float, array], /) -> array: + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the difference for each element of an array instance with the respective element of the array ``other``. @@ -970,7 +970,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (minuend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -988,7 +988,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __truediv__(self: array, other: Union[int, float, array], /) -> array: + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -1001,7 +1001,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns diff --git a/src/array_api_stubs/_2023_12/array_object.py b/src/array_api_stubs/_2023_12/array_object.py index f5cc9bcee..cac44d165 100644 --- a/src/array_api_stubs/_2023_12/array_object.py +++ b/src/array_api_stubs/_2023_12/array_object.py @@ -148,7 +148,7 @@ def __abs__(self: array, /) -> array: Added complex data type support. """ - def __add__(self: array, other: Union[int, float, array], /) -> array: + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the sum for each element of an array instance with the respective element of the array ``other``. @@ -156,7 +156,7 @@ def __add__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (augend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -494,7 +494,7 @@ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: ONE_API = 14 """ - def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: r""" Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -502,7 +502,7 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -513,6 +513,9 @@ def __eq__(self: array, other: Union[int, float, bool, array], /) -> array: .. note:: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __float__(self: array, /) -> float: @@ -893,7 +896,7 @@ def __mod__(self: array, other: Union[int, float, array], /) -> array: Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. """ - def __mul__(self: array, other: Union[int, float, array], /) -> array: + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates the product for each element of an array instance with the respective element of the array ``other``. @@ -904,7 +907,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -922,7 +925,7 @@ def __mul__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: """ Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -930,7 +933,7 @@ def __ne__(self: array, other: Union[int, float, bool, array], /) -> array: ---------- self: array array instance. May have any data type. - other: Union[int, float, bool, array] + other: Union[int, float, complex, bool, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. Returns @@ -1024,7 +1027,7 @@ def __pos__(self: array, /) -> array: Added complex data type support. """ - def __pow__(self: array, other: Union[int, float, array], /) -> array: + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. @@ -1037,7 +1040,7 @@ def __pow__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance whose elements correspond to the exponentiation base. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1081,7 +1084,7 @@ def __setitem__( key: Union[ int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array ], - value: Union[int, float, bool, array], + value: Union[int, float, complex, bool, array], /, ) -> None: """ @@ -1095,7 +1098,7 @@ def __setitem__( array instance. key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis], ...], array] index key. - value: Union[int, float, bool, array] + value: Union[int, float, complex, bool, array] value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). @@ -1108,7 +1111,7 @@ def __setitem__( When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. """ - def __sub__(self: array, other: Union[int, float, array], /) -> array: + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: """ Calculates the difference for each element of an array instance with the respective element of the array ``other``. @@ -1118,7 +1121,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance (minuend array). Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns @@ -1136,7 +1139,7 @@ def __sub__(self: array, other: Union[int, float, array], /) -> array: Added complex data type support. """ - def __truediv__(self: array, other: Union[int, float, array], /) -> array: + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: r""" Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. @@ -1149,7 +1152,7 @@ def __truediv__(self: array, other: Union[int, float, array], /) -> array: ---------- self: array array instance. Should have a numeric data type. - other: Union[int, float, array] + other: Union[int, float, complex, array] other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. Returns diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index 55ef60f07..ba5f99851 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -515,6 +515,9 @@ def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> ar - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. """ def __float__(self: array, /) -> float: From c91c82cec0f496372864b55bfe9fed57e73cbfb6 Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 03:13:48 -0800 Subject: [PATCH 547/551] docs: add design topic on `copy` keyword argument behavior PR-URL: https://github.com/data-apis/array-api/pull/906 Closes: https://github.com/data-apis/array-api/pull/886 Closes: https://github.com/data-apis/array-api/issues/866 Closes: https://github.com/data-apis/array-api/issues/495 Reviewed-by: Evgeni Burovski --- .../copies_views_and_mutation.rst | 109 +++++++++++------- src/array_api_stubs/_draft/array_object.py | 2 +- .../_draft/creation_functions.py | 2 +- .../_draft/data_type_functions.py | 2 +- .../_draft/manipulation_functions.py | 2 +- 5 files changed, 71 insertions(+), 46 deletions(-) diff --git a/spec/draft/design_topics/copies_views_and_mutation.rst b/spec/draft/design_topics/copies_views_and_mutation.rst index 1ca5a039c..f302d8c8e 100644 --- a/spec/draft/design_topics/copies_views_and_mutation.rst +++ b/spec/draft/design_topics/copies_views_and_mutation.rst @@ -1,6 +1,6 @@ .. _copyview-mutability: -Copy-view behaviour and mutability +Copy-view behavior and mutability ================================== .. admonition:: Mutating views @@ -10,11 +10,11 @@ Copy-view behaviour and mutability Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically have the concept of a "view", meaning an array containing data in memory that -belongs to another array (i.e. a different "view" on the original data). -Views are useful for performance reasons - not copying data to a new location -saves memory and is faster than copying - but can also affect the semantics +belongs to another array (i.e., a different "view" on the original data). +Views are useful for performance reasons—not copying data to a new location +saves memory and is faster than copying—but can also affect the semantics of code. This happens when views are combined with *mutating* operations. -This simple example illustrates that: +The following example is illustrative: .. code-block:: python @@ -22,56 +22,81 @@ This simple example illustrates that: y = x[:] # `y` *may* be a view on the data of `x` y -= 1 # if `y` is a view, this modifies `x` -Code as simple as the above example will not be portable between array -libraries - for NumPy/PyTorch/CuPy/MXNet ``x`` will contain the value ``0``, -while for TensorFlow/JAX/Dask it will contain the value ``1``. The combination -of views and mutability is fundamentally problematic here if the goal is to -be able to write code with unambiguous semantics. +Code similar to the above example will not be portable between array +libraries. For example, for NumPy, PyTorch, and CuPy, ``x`` will contain the value ``0``, +while, for TensorFlow, JAX, and Dask, ``x`` will contain the value ``1``. In +this case, the combination of views and mutability is fundamentally problematic +if the goal is to be able to write code with unambiguous semantics. Views are necessary for getting good performance out of the current strided -array libraries. It is not always clear however when a library will return a -view, and when it will return a copy. This API standard does not attempt to -specify this - libraries can do either. +array libraries. It is not always clear, however, when a library will return a +view and when it will return a copy. This standard does not attempt to +specify this—libraries may do either. -There are several types of operations that do in-place mutation of data -contained in arrays. These include: +There are several types of operations that may perform in-place mutation of +array data. These include: -1. Inplace operators (e.g. ``*=``) +1. In-place operators (e.g. ``*=``) 2. Item assignment (e.g. ``x[0] = 1``) 3. Slice assignment (e.g., ``x[:2, :] = 3``) 4. The `out=` keyword present in some strided array libraries (e.g. ``sin(x, out=y)``) -Libraries like TensorFlow and JAX tend to support inplace operators, provide +Libraries such as TensorFlow and JAX tend to support in-place operators by providing alternative syntax for item and slice assignment (e.g. an ``update_index`` -function or ``x.at[idx].set(y)``), and have no need for ``out=``. +function or ``x.at[idx].set(y)``) and have no need for ``out=``. -A potential solution could be to make views read-only, or use copy-on-write -semantics. Both are hard to implement and would present significant issues -for backwards compatibility for current strided array libraries. Read-only -views would also not be a full solution, given that mutating the original -(base) array will also result in ambiguous semantics. Hence this API standard -does not attempt to go down this route. +A potential solution could be to make views read-only or implement copy-on-write +semantics. Both are hard to implement and would present significant backward +compatibility issues for current strided array libraries. Read-only +views would also not be a full solution due to the fact that mutating the original +(base) array will also result in ambiguous semantics. Accordingly, this standard +does not attempt to pursue this solution. -Both inplace operators and item/slice assignment can be mapped onto +Both in-place operators and item/slice assignment can be mapped onto equivalent functional expressions (e.g. ``x[idx] = val`` maps to -``x.at[idx].set(val)``), and given that both inplace operators and item/slice +``x.at[idx].set(val)``), and, given that both in-place operators and item/slice assignment are very widely used in both library and end user code, this standard chooses to include them. -The situation with ``out=`` is slightly different - it's less heavily used, and -easier to avoid. It's also not an optimal API, because it mixes an +The situation with ``out=`` is slightly different—it's less heavily used, and +easier to avoid. It's also not an optimal API because it mixes an "efficiency of implementation" consideration ("you're allowed to do this -inplace") with the semantics of a function ("the output _must_ be placed into -this array). There are libraries that do some form of tracing or abstract -interpretation over a language that does not support mutation (to make -analysis easier); in those cases implementing ``out=`` with correct handling of -views may even be impossible to do. There's alternatives, for example the -donated arguments in JAX or working buffers in LAPACK, that allow the user to -express "you _may_ overwrite this data, do whatever is fastest". Given that -those alternatives aren't widely used in array libraries today, this API -standard chooses to (a) leave out ``out=``, and (b) not specify another method -of reusing arrays that are no longer needed as buffers. - -This leaves the problem of the initial example - with this API standard it -remains possible to write code that will not work the same for all array -libraries. This is something that the user must be careful about. +in-place") with the semantics of a function ("the output _must_ be placed into +this array"). There are libraries that do some form of tracing or abstract +interpretation over a vocabulary that does not support mutation (to make +analysis easier). In those cases implementing ``out=`` with correct handling of +views may even be impossible to do. + +There are alternatives. For example, the concept of donated arguments in JAX or +working buffers in LAPACK which allow the user to express "you _may_ overwrite +this data; do whatever is fastest". Given that those alternatives aren't widely +used in array libraries today, this standard chooses to (a) leave out ``out=``, +and (b) not specify another method of reusing arrays that are no longer needed +as buffers. + +This leaves the problem of the initial example—despite the best efforts of this +standard, it remains possible to write code that will not work the same for all +array libraries. This is something that the users are advised to best keep in +mind and to reason carefully about the potential ambiguity of implemented code. + + +.. _copy-keyword-argument: + +Copy keyword argument behavior +------------------------------ + +Several APIs in this standard support a ``copy`` keyword argument (e.g., +``asarray``, ``astype``, ``reshape``, and ``__dlpack__``). Typically, when a +user sets ``copy=True``, the user does so in order to ensure that they are free +to mutate the returned array without side-effects—namely, without mutating other +views on the original (base) array. Accordingly, when ``copy=True``, unless an +array library can guarantee that an array can be mutated without side-effects, +conforming libraries are recommended to always perform a physical copy of the +underlying array data. + +.. note:: + Typically, in order to provide such a guarantee, libraries must perform + whole-program analysis. + +Conversely, consumers of this standard should expect that, if they set +``copy=True``, they are free to use in-place operations on a returned array. diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index ba5f99851..ca1422bf9 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -370,7 +370,7 @@ def __dlpack__( API standard. copy: Optional[bool] boolean indicating whether or not to copy the input. If ``True``, the - function must always copy (performed by the producer). If ``False``, the + function must always copy (performed by the producer; see also :ref:`copy-keyword-argument`). If ``False``, the function must never copy, and raise a ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index 6de79268e..c09800783 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -111,7 +111,7 @@ def asarray( device: Optional[device] device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. copy: Optional[bool] - boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + boolean indicating whether or not to copy the input. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. Returns ------- diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index db793c16e..d7ae3caee 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -43,7 +43,7 @@ def astype( dtype: dtype desired data type. copy: bool - specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned. If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned (see :ref:`copy-keyword-argument`). If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. device: Optional[device] device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 7e94cbc27..1fc178e20 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -230,7 +230,7 @@ def reshape( shape: Tuple[int, ...] a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. copy: Optional[bool] - whether or not to copy the input array. If ``True``, the function must always copy. If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. + whether or not to copy the input array. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. Returns ------- From 4e402cc917cbe8d096dcb5817e836ce3be7a1e3b Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 03:24:01 -0800 Subject: [PATCH 548/551] docs: add changelog for v2024.12 specification revision PR-URL: https://github.com/data-apis/array-api/pull/903 Reviewed-by: Evgeni Burovski --- CHANGELOG.md | 166 ++++++++++++++++++ src/array_api_stubs/_draft/array_object.py | 25 ++- .../_draft/data_type_functions.py | 9 + .../_draft/elementwise_functions.py | 117 ++++++++++++ src/array_api_stubs/_draft/fft.py | 6 + .../_draft/indexing_functions.py | 8 + src/array_api_stubs/_draft/info.py | 3 + src/array_api_stubs/_draft/linalg.py | 3 + .../_draft/manipulation_functions.py | 3 + .../_draft/searching_functions.py | 10 +- .../_draft/statistical_functions.py | 8 + .../_draft/utility_functions.py | 2 + 12 files changed, 358 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d69bbc23..0919472d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,172 @@ This changelog is organized by specification version and notes all changes with respect to the previous version. Within the section for a specific version (e.g., v2022.12), separate sections are used for (a) changes to existing APIs and requirements, (b) new APIs and new requirements, and (c) errata. +## v2024.12 + +### Updates + +> Updates to existing APIs and requirements. + +#### Normative + +- Clarify that conforming implementations may support additional arguments beyond those described in the Array API specification ([gh-870](https://github.com/data-apis/array-api/pull/870)) +- Clarify accuracy requirements for operations involving complex numbers ([gh-882](https://github.com/data-apis/array-api/pull/882)) +- Clarify expected results for in-place operations in conforming array libraries which do not support array mutation ([gh-895](https://github.com/data-apis/array-api/pull/895)) + +#### APIs + +- `__dlpack__`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `__eq__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__ge__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__getitem__`: clarify that iteration is defined for one-dimensional arrays ([gh-821](https://github.com/data-apis/array-api/pull/821)) +- `__gt__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__le__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__lt__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `__ne__`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `asarray`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `astype`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `clip`: specify behavior when one of the operands is `NaN` ([gh-813](https://github.com/data-apis/array-api/pull/813); backported to v2023.12 revision of the Array API specification) +- `clip`: clarify behavior when arguments have different data types ([gh-896](https://github.com/data-apis/array-api/pull/896)) +- `conj`: add support for real-valued arrays ([gh-884](https://github.com/data-apis/array-api/pull/884)) +- `cumulative_sum`: clarify that behavior when providing a zero-dimensional array is unspecified ([gh-851](https://github.com/data-apis/array-api/pull/851)) +- `equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `greater`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `greater_equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `less`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `less_equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `mean`: add support for complex floating-point data types ([gh-850](https://github.com/data-apis/array-api/pull/850)) +- `not_equal`: clarify that cross-kind comparisons are unspecified ([gh-822](https://github.com/data-apis/array-api/pull/822)) +- `real`: add support for real-valued arrays ([gh-884](https://github.com/data-apis/array-api/pull/884)) +- `reshape`: clarify the expected behavior of the `copy` keyword argument when `copy=True` ([gh-906](https://github.com/data-apis/array-api/pull/906)) +- `sqrt`: clarify that results must be correctly rounded according to IEEE 754 ([gh-882](https://github.com/data-apis/array-api/pull/882)) +- `take`: clarify that behavior when provided a zero-dimensional input array is unspecified ([gh-876](https://github.com/data-apis/array-api/pull/876)) +- `take`: clarify support for negative indices ([gh-894](https://github.com/data-apis/array-api/pull/894)) + +##### Scalar Argument Support + +The following APIs were updated to support both scalar and array arguments for one or more arguments: + +- `add` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `atan2` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_and` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_left_shift` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_or` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_right_shift` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `bitwise_xor` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `copysign` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `divide` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `floor_divide` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `greater` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `greater_equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `hypot` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `less` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `less_equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logaddexp` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logical_and` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logical_or` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `logical_xor` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `maximum` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `minimum` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `multiply` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `nextafter` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `not_equal` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `pow` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `remainder` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `result_type` ([gh-873](https://github.com/data-apis/array-api/pull/873)) +- `subtract` ([gh-862](https://github.com/data-apis/array-api/pull/862)) +- `where` ([gh-860](https://github.com/data-apis/array-api/pull/860)) + +#### Extensions + +> Updates to APIs and requirements included as part of specification extensions. + +- `fft.fftfreq`: add `dtype` keyword argument ([gh-885](https://github.com/data-apis/array-api/pull/885)) +- `fft.rfftfreq`: add `dtype` keyword argument ([gh-885](https://github.com/data-apis/array-api/pull/885)) + +* * * + +### Additions + +> New APIs and requirements added to the specification. + +#### Normative + +- Add support for integer array indexing ([gh-900](https://github.com/data-apis/array-api/pull/900)) + +#### APIs + +The following APIs were added to the specification: + +- `count_nonzero`: count the number of array elements which are non-zero ([gh-803](https://github.com/data-apis/array-api/pull/803)) +- `cumulative_prod`: calculate the cumulative product ([gh-793](https://github.com/data-apis/array-api/pull/793)) +- `diff`: calculate the n-th discrete forward difference along a specified axis ([gh-791](https://github.com/data-apis/array-api/pull/791), [gh-881](https://github.com/data-apis/array-api/pull/881)) +- `nextafter`: return the next representable floating-point value for each element in an array ([gh-792](https://github.com/data-apis/array-api/pull/792)) +- `reciprocal`: return the reciprocal for each element in an array ([gh-802](https://github.com/data-apis/array-api/pull/802)) +- `take_along_axis`: return elements from an array at locations specified by one-dimensional indices along an axis ([gh-816](https://github.com/data-apis/array-api/pull/816)) + +#### Inspection APIs + +The following inspection APIs were added to the specification: + +- `max dimensions`: return the maximum number of supported dimensions ([gh-763](https://github.com/data-apis/array-api/pull/763) and [gh-809](https://github.com/data-apis/array-api/pull/809)) + +* * * + +### Breaking Changes + +The following is a list of breaking changes relative to the previous version of the specification: + +#### Normative + +- An operation involving a Python `complex` scalar and a real-valued floating-point arrays must be equivalent to an operation involving a zero-dimensional array having a complex floating-point data type and a real-valued floating-point array ([gh-871](https://github.com/data-apis/array-api/pull/871)) + +#### APIs + +- `can_cast`: application of type promotion rules must account for device context ([gh-889](https://github.com/data-apis/array-api/pull/889)) +- `result_type`: application of type promotion rules must account for device context ([gh-889](https://github.com/data-apis/array-api/pull/889)) + +* * * + +### Errata + +The following is a list of fixes and points of clarification with regard to the previous version of the specification: + +- `__add__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__bool__`: fix typo in special case notes ([gh-785](https://github.com/data-apis/array-api/pull/785)) +- `__dlpack__`: resolve conflicting exception guidance ([gh-887](https://github.com/data-apis/array-api/pull/887)) +- `__eq__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__getitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) +- `__mul__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__ne__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__pow__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__setitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) +- `__setitem__`: fix typing for `value` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__sub__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__truediv__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `broadcast_to`: clarify broadcast behavior ([gh-888](https://github.com/data-apis/array-api/pull/888)) +- `broadcast_to`: clarify required exception behavior ([gh-897](https://github.com/data-apis/array-api/pull/897)) +- `clip`: clarify that the operation is only defined when elements in `min` and `max` are inside the bounds of the input array data type ([gh-814](https://github.com/data-apis/array-api/pull/814)) +- `clip`: fix typo in parameter description ([gh-896](https://github.com/data-apis/array-api/pull/896)) +- `copysign`: fix formatting of special cases ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.fft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.ifft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.fftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.ifftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.irfft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.irfftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `fft.hfft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) +- `linalg.solve`: clarify broadcasting semantics and output shape ([gh-810](https://github.com/data-apis/array-api/pull/810)) +- `nonzero`: fix return type ([gh-803](https://github.com/data-apis/array-api/pull/803) and [gh-https://github.com/data-apis/array-api/pull/904](https://github.com/data-apis/array-api/pull/904)) +- `searchsorted`: fix incorrect boundary conditions ([gh-898](https://github.com/data-apis/array-api/pull/898)) +- `sign`: fix equation in function description ([gh-844](https://github.com/data-apis/array-api/pull/844)) +- `tile`: fix missing return type ([gh-798](https://github.com/data-apis/array-api/pull/798)) +- `unstack`: fix typo in function description ([gh-810](https://github.com/data-apis/array-api/pull/810)) +- `vecdot`: fix regression in default value for `axis` keyword argument ([gh-880](https://github.com/data-apis/array-api/pull/880)) +- `where`: clarify that the `condition` argument should have a boolean data type ([gh-868](https://github.com/data-apis/array-api/pull/868)) + +* * * + ## v2023.12 ### Updates diff --git a/src/array_api_stubs/_draft/array_object.py b/src/array_api_stubs/_draft/array_object.py index ca1422bf9..08d5c0b6e 100644 --- a/src/array_api_stubs/_draft/array_object.py +++ b/src/array_api_stubs/_draft/array_object.py @@ -460,10 +460,13 @@ def __dlpack__( Added BufferError. .. versionchanged:: 2023.12 - Added the ``max_version``, ``dl_device``, and ``copy`` keywords. + Added the ``max_version``, ``dl_device``, and ``copy`` keyword arguments. .. versionchanged:: 2023.12 Added recommendation for handling read-only arrays. + + .. versionchanged:: 2024.12 + Resolved conflicting exception guidance. """ def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: @@ -518,6 +521,9 @@ def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> ar .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __float__(self: array, /) -> float: @@ -604,6 +610,9 @@ def __ge__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __getitem__( @@ -639,6 +648,8 @@ def __getitem__( - See :ref:`indexing` for details on supported indexing semantics. - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + .. versionchanged:: 2024.12 + Clarified that iteration is defined for one-dimensional arrays. """ def __gt__(self: array, other: Union[int, float, array], /) -> array: @@ -663,6 +674,9 @@ def __gt__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __index__(self: array, /) -> int: @@ -784,6 +798,9 @@ def __le__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __lshift__(self: array, other: Union[int, array], /) -> array: @@ -830,6 +847,9 @@ def __lt__(self: array, other: Union[int, float, array], /) -> array: - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __matmul__(self: array, other: array, /) -> array: @@ -955,6 +975,9 @@ def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> ar .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. """ def __neg__(self: array, /) -> array: diff --git a/src/array_api_stubs/_draft/data_type_functions.py b/src/array_api_stubs/_draft/data_type_functions.py index d7ae3caee..7a6c59d94 100644 --- a/src/array_api_stubs/_draft/data_type_functions.py +++ b/src/array_api_stubs/_draft/data_type_functions.py @@ -84,6 +84,9 @@ def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: - When ``from_`` is a data type, the function must determine whether the data type can be cast to another data type according to the complete type promotion rules (see :ref:`type-promotion`) described in this specification, irrespective of whether a conforming array library supports devices which do not have full data type support. - When ``from_`` is an array, the function must determine whether the data type of the array can be cast to the desired data type according to the type promotion graph of the array device. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the output of ``can_cast(array, dtype)`` may differ from ``can_cast(array.dtype, dtype)``. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. """ @@ -238,4 +241,10 @@ def result_type( - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and thus implementation-dependent. - If at least one argument is an array, the function must determine the resulting dtype according to the type promotion graph of the array device which is shared among all array arguments. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the returned dtype may differ from that determined from the complete type promotion graph defined in this specification (see :ref:`type-promotion`). - If two or more arguments are arrays belonging to different devices, behavior is unspecified and thus implementation-dependent. Conforming implementations may choose to ignore device attributes, raise an exception, or some other behavior. + + .. versionchanged:: 2024.12 + Added scalar argument support. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. """ diff --git a/src/array_api_stubs/_draft/elementwise_functions.py b/src/array_api_stubs/_draft/elementwise_functions.py index a35c04db5..2f0cfc8c3 100644 --- a/src/array_api_stubs/_draft/elementwise_functions.py +++ b/src/array_api_stubs/_draft/elementwise_functions.py @@ -341,6 +341,9 @@ def add( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -573,6 +576,9 @@ def atan2(x1: Union[array, int, float], x2: Union[array, int, float], /) -> arra - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -665,6 +671,9 @@ def bitwise_and(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -688,6 +697,9 @@ def bitwise_left_shift(x1: Union[array, int], x2: Union[array, int], /) -> array ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -727,6 +739,9 @@ def bitwise_or(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> a ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -753,6 +768,9 @@ def bitwise_right_shift(x1: Union[array, int], x2: Union[array, int], /) -> arra ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -776,6 +794,9 @@ def bitwise_xor(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -850,6 +871,15 @@ def clip( - If ``max_i`` is ``NaN``, the result is ``NaN``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added special case behavior when one of the operands is ``NaN``. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when ``x``, ``min``, and ``max`` resolve to arrays having the same data type. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when elements of ``min`` and ``max`` are inside the bounds of the input array data type. """ @@ -885,6 +915,9 @@ def conj(x: array, /) -> array: - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. """ @@ -928,6 +961,9 @@ def copysign(x1: Union[array, int, float], x2: Union[array, int, float], /) -> a - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1124,6 +1160,9 @@ def divide( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1177,6 +1216,12 @@ def equal( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1385,6 +1430,9 @@ def floor_divide( - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1411,6 +1459,11 @@ def greater(x1: Union[array, int, float], x2: Union[array, int, float], /) -> ar - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1438,6 +1491,12 @@ def greater_equal( - At least one of ``x1`` or ``x2`` must be an array. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1486,6 +1545,9 @@ def hypot(x1: Union[array, int, float], x2: Union[array, int, float], /) -> arra Accordingly, conforming implementations may vary in their support for subnormal numbers. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1638,6 +1700,12 @@ def less(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array - At least one of ``x1`` or ``x2`` must be an array. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1663,6 +1731,12 @@ def less_equal(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - At least one of ``x1`` or ``x2`` must be an array. - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1902,6 +1976,9 @@ def logaddexp(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1928,6 +2005,9 @@ def logical_and(x1: Union[array, bool], x2: Union[array, bool], /) -> array: ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1973,6 +2053,9 @@ def logical_or(x1: Union[array, bool], x2: Union[array, bool], /) -> array: ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -1999,6 +2082,9 @@ def logical_xor(x1: Union[array, bool], x2: Union[array, bool], /) -> array: ----- - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2032,6 +2118,9 @@ def maximum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> ar - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2065,6 +2154,9 @@ def minimum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> ar - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2137,6 +2229,9 @@ def multiply( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2196,6 +2291,8 @@ def nextafter(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``-0``. + + .. versionadded:: 2024.12 """ @@ -2247,6 +2344,12 @@ def not_equal( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2341,6 +2444,9 @@ def pow( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2364,6 +2470,9 @@ def real(x: array, /) -> array: - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. """ @@ -2387,6 +2496,8 @@ def reciprocal(x: array, /) -> array: **Special cases** For floating-point operands, special cases must be handled as if the operation is implemented as ``1.0 / x`` (see :func:`~array_api.divide`). + + .. versionadded:: 2024.12 """ @@ -2442,6 +2553,9 @@ def remainder(x1: Union[array, int, float], x2: Union[array, int, float], /) -> - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) - In the remaining cases, the result must match that of the Python ``%`` operator. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ @@ -2796,6 +2910,9 @@ def subtract( .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. """ diff --git a/src/array_api_stubs/_draft/fft.py b/src/array_api_stubs/_draft/fft.py index 3d1f4d9c7..0924b2f9c 100644 --- a/src/array_api_stubs/_draft/fft.py +++ b/src/array_api_stubs/_draft/fft.py @@ -592,6 +592,9 @@ def fftfreq( .. versionchanged:: 2023.12 Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. """ @@ -638,6 +641,9 @@ def rfftfreq( .. versionchanged:: 2023.12 Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. """ diff --git a/src/array_api_stubs/_draft/indexing_functions.py b/src/array_api_stubs/_draft/indexing_functions.py index 8be7cc00e..8e4fae25f 100644 --- a/src/array_api_stubs/_draft/indexing_functions.py +++ b/src/array_api_stubs/_draft/indexing_functions.py @@ -34,6 +34,12 @@ def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: .. versionchanged:: 2023.12 Out-of-bounds behavior is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Behavior when provided a zero-dimensional input array is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Clarified support for negative indices. """ @@ -59,4 +65,6 @@ def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: ----- - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + .. versionadded:: 2024.12 """ diff --git a/src/array_api_stubs/_draft/info.py b/src/array_api_stubs/_draft/info.py index 6177fb12f..fc8b302a8 100644 --- a/src/array_api_stubs/_draft/info.py +++ b/src/array_api_stubs/_draft/info.py @@ -69,6 +69,9 @@ def capabilities() -> Capabilities: ----- .. versionadded: 2023.12 + + .. versionchanged:: 2024.12 + Added support for querying the maximum number of supported dimensions. """ diff --git a/src/array_api_stubs/_draft/linalg.py b/src/array_api_stubs/_draft/linalg.py index a43dc8dcf..4086c333e 100644 --- a/src/array_api_stubs/_draft/linalg.py +++ b/src/array_api_stubs/_draft/linalg.py @@ -635,6 +635,9 @@ def solve(x1: array, x2: array, /) -> array: .. versionchanged:: 2022.12 Added complex data type support. + + .. versionchanged:: 2024.12 + Clarified broadcasting semantics and the shape of the output array. """ diff --git a/src/array_api_stubs/_draft/manipulation_functions.py b/src/array_api_stubs/_draft/manipulation_functions.py index 1fc178e20..dd8d4cd69 100644 --- a/src/array_api_stubs/_draft/manipulation_functions.py +++ b/src/array_api_stubs/_draft/manipulation_functions.py @@ -50,6 +50,9 @@ def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: ------- out: array an array having the specified shape. Must have the same data type as ``x``. + + .. versionchanged:: 2024.12 + Clarified broadcast behavior. """ diff --git a/src/array_api_stubs/_draft/searching_functions.py b/src/array_api_stubs/_draft/searching_functions.py index d8676b68b..2478cda11 100644 --- a/src/array_api_stubs/_draft/searching_functions.py +++ b/src/array_api_stubs/_draft/searching_functions.py @@ -83,6 +83,8 @@ def count_nonzero( - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. versionadded:: 2024.12 """ @@ -162,6 +164,9 @@ def searchsorted( While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Fixed incorrect boundary conditions. """ @@ -195,5 +200,8 @@ def where( - If either ``x1`` or ``x2`` is a scalar value, the returned array must have a data type determined according to :ref:`mixing-scalars-and-arrays`. .. versionchanged:: 2024.12 - Added support for scalar arguments. + Added scalar argument support. + + .. versionchanged:: 2024.12 + Clarified that the ``condition`` argument should have a boolean data type. """ diff --git a/src/array_api_stubs/_draft/statistical_functions.py b/src/array_api_stubs/_draft/statistical_functions.py index 92ffe60c5..d318f6d2a 100644 --- a/src/array_api_stubs/_draft/statistical_functions.py +++ b/src/array_api_stubs/_draft/statistical_functions.py @@ -63,6 +63,8 @@ def cumulative_prod( **Special Cases** For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionadded:: 2024.12 """ @@ -117,6 +119,9 @@ def cumulative_sum( For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Behavior when providing a zero-dimensional array is explicitly left unspecified. """ @@ -209,6 +214,9 @@ def mean( .. note:: Array libraries, such as NumPy, PyTorch, and JAX, currently deviate from this specification in their handling of components which are ``NaN`` when computing the arithmetic mean. In general, consumers of array libraries implementing this specification should use :func:`~array_api.isnan` to test whether the result of computing the arithmetic mean over an array have a complex floating-point data type is ``NaN``, rather than relying on ``NaN`` propagation of individual components. + + .. versionchanged:: 2024.12 + Added complex data type support. """ diff --git a/src/array_api_stubs/_draft/utility_functions.py b/src/array_api_stubs/_draft/utility_functions.py index 7a234efbb..539833356 100644 --- a/src/array_api_stubs/_draft/utility_functions.py +++ b/src/array_api_stubs/_draft/utility_functions.py @@ -126,4 +126,6 @@ def diff( - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). - If a conforming implementation chooses to support ``prepend`` and ``append`` arrays which have a different data type than ``x``, behavior is unspecified and thus implementation-defined. Implementations may choose to type promote (:ref:`type-promotion`), cast ``prepend`` and/or ``append`` to the same data type as ``x``, or raise an exception. + + .. versionadded:: 2024.12 """ From aa9e0e9be2f1827c027bae1e3fad64d5a6b2a238 Mon Sep 17 00:00:00 2001 From: Athan Reines Date: Wed, 26 Feb 2025 16:45:22 -0800 Subject: [PATCH 549/551] build: create new release --- LICENSE | 2 +- Makefile | 3 +- .../API_specification/array_object.rst | 322 ++ .../API_specification/broadcasting.rst | 128 + spec/2024.12/API_specification/constants.rst | 26 + .../API_specification/creation_functions.rst | 36 + .../API_specification/data_type_functions.rst | 26 + spec/2024.12/API_specification/data_types.rst | 143 + .../elementwise_functions.rst | 86 + .../function_and_method_signatures.rst | 63 + spec/2024.12/API_specification/index.rst | 41 + spec/2024.12/API_specification/indexing.rst | 253 ++ .../API_specification/indexing_functions.rst | 24 + spec/2024.12/API_specification/inspection.rst | 42 + .../linear_algebra_functions.rst | 23 + .../manipulation_functions.rst | 34 + .../API_specification/searching_functions.rst | 28 + .../API_specification/set_functions.rst | 24 + .../API_specification/sorting_functions.rst | 31 + .../statistical_functions.rst | 29 + .../API_specification/type_promotion.rst | 163 + .../API_specification/utility_functions.rst | 23 + spec/2024.12/API_specification/version.rst | 22 + spec/2024.12/assumptions.md | 77 + spec/2024.12/benchmark_suite.md | 3 + spec/2024.12/changelog.rst | 5 + spec/2024.12/conf.py | 13 + spec/2024.12/design_topics/C_API.rst | 94 + spec/2024.12/design_topics/accuracy.rst | 93 + .../2024.12/design_topics/complex_numbers.rst | 61 + .../copies_views_and_mutation.rst | 102 + .../data_dependent_output_shapes.rst | 15 + .../design_topics/data_interchange.rst | 105 + spec/2024.12/design_topics/device_support.rst | 112 + spec/2024.12/design_topics/exceptions.rst | 28 + spec/2024.12/design_topics/index.rst | 18 + spec/2024.12/design_topics/lazy_eager.rst | 43 + spec/2024.12/design_topics/parallelism.rst | 24 + spec/2024.12/design_topics/static_typing.rst | 50 + .../fourier_transform_functions.rst | 45 + spec/2024.12/extensions/index.rst | 34 + .../extensions/linear_algebra_functions.rst | 116 + spec/2024.12/future_API_evolution.md | 60 + spec/2024.12/index.rst | 37 + spec/2024.12/license.rst | 9 + spec/2024.12/purpose_and_scope.md | 470 +++ spec/2024.12/usage_data.md | 86 + spec/2024.12/use_cases.md | 235 ++ spec/2024.12/verification_test_suite.md | 62 + spec/_ghpages/versions.json | 1 + src/_array_api_conf.py | 2 +- src/array_api_stubs/_2024_12/__init__.py | 25 + src/array_api_stubs/_2024_12/_types.py | 149 + src/array_api_stubs/_2024_12/array_object.py | 1250 +++++++ src/array_api_stubs/_2024_12/constants.py | 30 + .../_2024_12/creation_functions.py | 647 ++++ .../_2024_12/data_type_functions.py | 250 ++ src/array_api_stubs/_2024_12/data_types.py | 22 + .../_2024_12/elementwise_functions.py | 3060 +++++++++++++++++ src/array_api_stubs/_2024_12/fft.py | 707 ++++ .../_2024_12/indexing_functions.py | 70 + src/array_api_stubs/_2024_12/info.py | 203 ++ src/array_api_stubs/_2024_12/linalg.py | 853 +++++ .../_2024_12/linear_algebra_functions.py | 166 + .../_2024_12/manipulation_functions.py | 371 ++ .../_2024_12/searching_functions.py | 207 ++ src/array_api_stubs/_2024_12/set_functions.py | 183 + .../_2024_12/sorting_functions.py | 58 + .../_2024_12/statistical_functions.py | 455 +++ .../_2024_12/utility_functions.py | 131 + src/array_api_stubs/__init__.py | 2 +- 71 files changed, 12407 insertions(+), 4 deletions(-) create mode 100644 spec/2024.12/API_specification/array_object.rst create mode 100644 spec/2024.12/API_specification/broadcasting.rst create mode 100644 spec/2024.12/API_specification/constants.rst create mode 100644 spec/2024.12/API_specification/creation_functions.rst create mode 100644 spec/2024.12/API_specification/data_type_functions.rst create mode 100644 spec/2024.12/API_specification/data_types.rst create mode 100644 spec/2024.12/API_specification/elementwise_functions.rst create mode 100644 spec/2024.12/API_specification/function_and_method_signatures.rst create mode 100644 spec/2024.12/API_specification/index.rst create mode 100644 spec/2024.12/API_specification/indexing.rst create mode 100644 spec/2024.12/API_specification/indexing_functions.rst create mode 100644 spec/2024.12/API_specification/inspection.rst create mode 100644 spec/2024.12/API_specification/linear_algebra_functions.rst create mode 100644 spec/2024.12/API_specification/manipulation_functions.rst create mode 100644 spec/2024.12/API_specification/searching_functions.rst create mode 100644 spec/2024.12/API_specification/set_functions.rst create mode 100644 spec/2024.12/API_specification/sorting_functions.rst create mode 100644 spec/2024.12/API_specification/statistical_functions.rst create mode 100644 spec/2024.12/API_specification/type_promotion.rst create mode 100644 spec/2024.12/API_specification/utility_functions.rst create mode 100644 spec/2024.12/API_specification/version.rst create mode 100644 spec/2024.12/assumptions.md create mode 100644 spec/2024.12/benchmark_suite.md create mode 100644 spec/2024.12/changelog.rst create mode 100644 spec/2024.12/conf.py create mode 100644 spec/2024.12/design_topics/C_API.rst create mode 100644 spec/2024.12/design_topics/accuracy.rst create mode 100644 spec/2024.12/design_topics/complex_numbers.rst create mode 100644 spec/2024.12/design_topics/copies_views_and_mutation.rst create mode 100644 spec/2024.12/design_topics/data_dependent_output_shapes.rst create mode 100644 spec/2024.12/design_topics/data_interchange.rst create mode 100644 spec/2024.12/design_topics/device_support.rst create mode 100644 spec/2024.12/design_topics/exceptions.rst create mode 100644 spec/2024.12/design_topics/index.rst create mode 100644 spec/2024.12/design_topics/lazy_eager.rst create mode 100644 spec/2024.12/design_topics/parallelism.rst create mode 100644 spec/2024.12/design_topics/static_typing.rst create mode 100644 spec/2024.12/extensions/fourier_transform_functions.rst create mode 100644 spec/2024.12/extensions/index.rst create mode 100644 spec/2024.12/extensions/linear_algebra_functions.rst create mode 100644 spec/2024.12/future_API_evolution.md create mode 100644 spec/2024.12/index.rst create mode 100644 spec/2024.12/license.rst create mode 100644 spec/2024.12/purpose_and_scope.md create mode 100644 spec/2024.12/usage_data.md create mode 100644 spec/2024.12/use_cases.md create mode 100644 spec/2024.12/verification_test_suite.md create mode 100644 src/array_api_stubs/_2024_12/__init__.py create mode 100644 src/array_api_stubs/_2024_12/_types.py create mode 100644 src/array_api_stubs/_2024_12/array_object.py create mode 100644 src/array_api_stubs/_2024_12/constants.py create mode 100644 src/array_api_stubs/_2024_12/creation_functions.py create mode 100644 src/array_api_stubs/_2024_12/data_type_functions.py create mode 100644 src/array_api_stubs/_2024_12/data_types.py create mode 100644 src/array_api_stubs/_2024_12/elementwise_functions.py create mode 100644 src/array_api_stubs/_2024_12/fft.py create mode 100644 src/array_api_stubs/_2024_12/indexing_functions.py create mode 100644 src/array_api_stubs/_2024_12/info.py create mode 100644 src/array_api_stubs/_2024_12/linalg.py create mode 100644 src/array_api_stubs/_2024_12/linear_algebra_functions.py create mode 100644 src/array_api_stubs/_2024_12/manipulation_functions.py create mode 100644 src/array_api_stubs/_2024_12/searching_functions.py create mode 100644 src/array_api_stubs/_2024_12/set_functions.py create mode 100644 src/array_api_stubs/_2024_12/sorting_functions.py create mode 100644 src/array_api_stubs/_2024_12/statistical_functions.py create mode 100644 src/array_api_stubs/_2024_12/utility_functions.py diff --git a/LICENSE b/LICENSE index fb491e886..8d3ac90e9 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2020-2024 Consortium for Python Data API Standards contributors +Copyright (c) 2020-2025 Consortium for Python Data API Standards contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 51e1fbf76..aa2212611 100644 --- a/Makefile +++ b/Makefile @@ -24,5 +24,6 @@ spec: sphinx-build "$(SOURCEDIR)/2021.12" "$(BUILDDIR)/2021.12" $(SPHINXOPTS) sphinx-build "$(SOURCEDIR)/2022.12" "$(BUILDDIR)/2022.12" $(SPHINXOPTS) sphinx-build "$(SOURCEDIR)/2023.12" "$(BUILDDIR)/2023.12" $(SPHINXOPTS) - cp -r "$(BUILDDIR)/2023.12" "$(BUILDDIR)/latest" + sphinx-build "$(SOURCEDIR)/2024.12" "$(BUILDDIR)/2024.12" $(SPHINXOPTS) + cp -r "$(BUILDDIR)/2024.12" "$(BUILDDIR)/latest" sphinx-build "$(SOURCEDIR)/draft" "$(BUILDDIR)/draft" $(SPHINXOPTS) diff --git a/spec/2024.12/API_specification/array_object.rst b/spec/2024.12/API_specification/array_object.rst new file mode 100644 index 000000000..e3c7e8ae6 --- /dev/null +++ b/spec/2024.12/API_specification/array_object.rst @@ -0,0 +1,322 @@ +.. _array-object: + +Array object +============ + + Array API specification for array object attributes and methods. + +A conforming implementation of the array API standard must provide and support an array object having the following attributes and methods. + +Furthermore, a conforming implementation of the array API standard must support, at minimum, array objects of rank (i.e., number of dimensions) ``0``, ``1``, ``2``, ``3``, and ``4`` and must explicitly document their maximum supported rank ``N``. + +.. note:: + Conforming implementations must support zero-dimensional arrays. + + Apart from array object attributes, such as ``ndim``, ``device``, and ``dtype``, all operations in this standard return arrays (or tuples of arrays), including those operations, such as ``mean``, ``var``, and ``std``, from which some common array libraries (e.g., NumPy) return scalar values. + + *Rationale: always returning arrays is necessary to (1) support accelerator libraries where non-array return values could force device synchronization and (2) support delayed execution models where an array represents a future value.* + +------------------------------------------------- + +.. _operators: + +Operators +--------- + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python operators. + +Arithmetic Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python arithmetic operators. + +- ``+x``: :meth:`.array.__pos__` + + - `operator.pos(x) `_ + - `operator.__pos__(x) `_ + +- `-x`: :meth:`.array.__neg__` + + - `operator.neg(x) `_ + - `operator.__neg__(x) `_ + +- `x1 + x2`: :meth:`.array.__add__` + + - `operator.add(x1, x2) `_ + - `operator.__add__(x1, x2) `_ + +- `x1 - x2`: :meth:`.array.__sub__` + + - `operator.sub(x1, x2) `_ + - `operator.__sub__(x1, x2) `_ + +- `x1 * x2`: :meth:`.array.__mul__` + + - `operator.mul(x1, x2) `_ + - `operator.__mul__(x1, x2) `_ + +- `x1 / x2`: :meth:`.array.__truediv__` + + - `operator.truediv(x1,x2) `_ + - `operator.__truediv__(x1, x2) `_ + +- `x1 // x2`: :meth:`.array.__floordiv__` + + - `operator.floordiv(x1, x2) `_ + - `operator.__floordiv__(x1, x2) `_ + +- `x1 % x2`: :meth:`.array.__mod__` + + - `operator.mod(x1, x2) `_ + - `operator.__mod__(x1, x2) `_ + +- `x1 ** x2`: :meth:`.array.__pow__` + + - `operator.pow(x1, x2) `_ + - `operator.__pow__(x1, x2) `_ + +Arithmetic operators should be defined for arrays having real-valued data types. + +Array Operators +~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python array operators. + +- `x1 @ x2`: :meth:`.array.__matmul__` + + - `operator.matmul(x1, x2) `_ + - `operator.__matmul__(x1, x2) `_ + +The matmul ``@`` operator should be defined for arrays having numeric data types. + +Bitwise Operators +~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python bitwise operators. + +- `~x`: :meth:`.array.__invert__` + + - `operator.inv(x) `_ + - `operator.invert(x) `_ + - `operator.__inv__(x) `_ + - `operator.__invert__(x) `_ + +- `x1 & x2`: :meth:`.array.__and__` + + - `operator.and(x1, x2) `_ + - `operator.__and__(x1, x2) `_ + +- `x1 | x2`: :meth:`.array.__or__` + + - `operator.or(x1, x2) `_ + - `operator.__or__(x1, x2) `_ + +- `x1 ^ x2`: :meth:`.array.__xor__` + + - `operator.xor(x1, x2) `_ + - `operator.__xor__(x1, x2) `_ + +- `x1 << x2`: :meth:`.array.__lshift__` + + - `operator.lshift(x1, x2) `_ + - `operator.__lshift__(x1, x2) `_ + +- `x1 >> x2`: :meth:`.array.__rshift__` + + - `operator.rshift(x1, x2) `_ + - `operator.__rshift__(x1, x2) `_ + +Bitwise operators should be defined for arrays having integer and boolean data types. + +Comparison Operators +~~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following Python comparison operators. + +- `x1 < x2`: :meth:`.array.__lt__` + + - `operator.lt(x1, x2) `_ + - `operator.__lt__(x1, x2) `_ + +- `x1 <= x2`: :meth:`.array.__le__` + + - `operator.le(x1, x2) `_ + - `operator.__le__(x1, x2) `_ + +- `x1 > x2`: :meth:`.array.__gt__` + + - `operator.gt(x1, x2) `_ + - `operator.__gt__(x1, x2) `_ + +- `x1 >= x2`: :meth:`.array.__ge__` + + - `operator.ge(x1, x2) `_ + - `operator.__ge__(x1, x2) `_ + +- `x1 == x2`: :meth:`.array.__eq__` + + - `operator.eq(x1, x2) `_ + - `operator.__eq__(x1, x2) `_ + +- `x1 != x2`: :meth:`.array.__ne__` + + - `operator.ne(x1, x2) `_ + - `operator.__ne__(x1, x2) `_ + +:meth:`.array.__lt__`, :meth:`.array.__le__`, :meth:`.array.__gt__`, :meth:`.array.__ge__` are only defined for arrays having real-valued data types. Other comparison operators should be defined for arrays having any data type. +For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + +In-place Operators +~~~~~~~~~~~~~~~~~~ + +.. note:: + In-place operations must be supported as discussed in :ref:`copyview-mutability`. + +A conforming implementation of the array API standard must provide and support an array object supporting the following "in-place" Python operators. + +.. note:: + This specification refers to the following operators as "in-place" as that is what these operators are called in `Python `. However, conforming array libraries which do not support array mutation may choose to not explicitly implement in-place Python operators. When a library does not implement a method corresponding to an in-place Python operator, Python falls back to the equivalent method for the corresponding binary arithmetic operation. + +An in-place operation must not change the data type or shape of the in-place array as a result of :ref:`type-promotion` or :ref:`broadcasting`. + +Let ``x1 += x2`` be a representative in-place operation. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands ``x1`` and ``x2``, the resulting data type is equal to the data type of the array on the left-hand side of the operation (i.e., ``x1``), then an in-place operation must have the same behavior (including special cases) as the respective binary (i.e., two operand, non-assignment) operation. In this case, for the in-place addition ``x1 += x2``, the modified array ``x1`` must always equal the result of the equivalent binary arithmetic operation ``x1[...] = x1 + x2``. + +If, however, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of the array on the left-hand side of the operation, then a conforming implementation may return results which differ from the respective binary operation due to casting behavior and selection of the operation's intermediate precision. The choice of casting behavior and intermediate precision is unspecified and thus implementation-defined. + +.. note:: + Let ``x1`` be the operand on the left-hand side and ``x2`` be the operand on the right-hand side of an in-place operation. Consumers of the array API standard are advised of the following considerations when using in-place operations: + + 1. In-place operations do not guarantee in-place mutation. A conforming library may or may not support in-place mutation. + 2. If, after applying broadcasting (see :ref:`broadcasting`) to in-place operands, the resulting shape is not equal to the shape of ``x1``, in-place operators may raise an exception. + 3. If, after applying type promotion (see :ref:`type-promotion`) to in-place operands, the resulting data type is not equal to the data type of ``x1``, the resulting data type may not equal the data type of ``x1`` and the operation's intermediate precision may be that of ``x1``, even if the promoted data type between ``x1`` and ``x2`` would have higher precision. + + In general, for in-place operations, consumers of the array API standard are advised to ensure operands have the same data type and broadcast to the shape of the operand on the left-hand side of the operation in order to maximize portability. + +Arithmetic Operators +"""""""""""""""""""" + +- ``+=``. May be implemented via ``__iadd__``. +- ``-=``. May be implemented via ``__isub__``. +- ``*=``. May be implemented via ``__imul__``. +- ``/=``. May be implemented via ``__itruediv__``. +- ``//=``. May be implemented via ``__ifloordiv__``. +- ``**=``. May be implemented via ``__ipow__``. +- ``%=``. May be implemented via ``__imod__``. + +Array Operators +""""""""""""""" + +- ``@=``. May be implemented via ``__imatmul__``. + +Bitwise Operators +""""""""""""""""" + +- ``&=``. May be implemented via ``__iand__``. +- ``|=``. May be implemented via ``__ior__``. +- ``^=``. May be implemented via ``__ixor__``. +- ``<<=``. May be implemented via ``__ilshift__``. +- ``>>=``. May be implemented via ``__irshift__``. + +Reflected Operators +~~~~~~~~~~~~~~~~~~~ + +A conforming implementation of the array API standard must provide and support an array object supporting the following reflected operators. + +The results of applying reflected operators must match their non-reflected equivalents. + +.. note:: + All operators for which ``array scalar`` is implemented must have an equivalent reflected operator implementation. + +Arithmetic Operators +"""""""""""""""""""" + +- ``__radd__`` +- ``__rsub__`` +- ``__rmul__`` +- ``__rtruediv__`` +- ``__rfloordiv__`` +- ``__rpow__`` +- ``__rmod__`` + +Array Operators +""""""""""""""" + +- ``__rmatmul__`` + +Bitwise Operators +""""""""""""""""" + +- ``__rand__`` +- ``__ror__`` +- ``__rxor__`` +- ``__rlshift__`` +- ``__rrshift__`` + +------------------------------------------------- + +.. currentmodule:: array_api + +Attributes +---------- +.. + NOTE: please keep the attributes in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.dtype + array.device + array.mT + array.ndim + array.shape + array.size + array.T + +------------------------------------------------- + +Methods +------- +.. + NOTE: please keep the methods in alphabetical order + + +.. autosummary:: + :toctree: generated + :template: property.rst + + array.__abs__ + array.__add__ + array.__and__ + array.__array_namespace__ + array.__bool__ + array.__complex__ + array.__dlpack__ + array.__dlpack_device__ + array.__eq__ + array.__float__ + array.__floordiv__ + array.__ge__ + array.__getitem__ + array.__gt__ + array.__index__ + array.__int__ + array.__invert__ + array.__le__ + array.__lshift__ + array.__lt__ + array.__matmul__ + array.__mod__ + array.__mul__ + array.__ne__ + array.__neg__ + array.__or__ + array.__pos__ + array.__pow__ + array.__rshift__ + array.__setitem__ + array.__sub__ + array.__truediv__ + array.__xor__ + array.to_device diff --git a/spec/2024.12/API_specification/broadcasting.rst b/spec/2024.12/API_specification/broadcasting.rst new file mode 100644 index 000000000..abb3ed222 --- /dev/null +++ b/spec/2024.12/API_specification/broadcasting.rst @@ -0,0 +1,128 @@ +.. _broadcasting: + +Broadcasting +============ + + Array API specification for broadcasting semantics. + +Overview +-------- + +**Broadcasting** refers to the automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +Broadcasting facilitates user ergonomics by encouraging users to avoid unnecessary copying of array data and can **potentially** enable more memory-efficient element-wise operations through vectorization, reduced memory consumption, and cache locality. + +Algorithm +--------- + +Given an element-wise operation involving two compatible arrays, an array having a singleton dimension (i.e., a dimension whose size is one) is broadcast (i.e., virtually repeated) across an array having a corresponding non-singleton dimension. + +If two arrays are of unequal rank, the array having a lower rank is promoted to a higher rank by (virtually) prepending singleton dimensions until the number of dimensions matches that of the array having a higher rank. + +The results of the element-wise operation must be stored in an array having a shape determined by the following algorithm. + +#. Let ``A`` and ``B`` both be arrays. + +#. Let ``shape1`` be a tuple describing the shape of array ``A``. + +#. Let ``shape2`` be a tuple describing the shape of array ``B``. + +#. Let ``N1`` be the number of dimensions of array ``A`` (i.e., the result of ``len(shape1)``). + +#. Let ``N2`` be the number of dimensions of array ``B`` (i.e., the result of ``len(shape2)``). + +#. Let ``N`` be the maximum value of ``N1`` and ``N2`` (i.e., the result of ``max(N1, N2)``). + +#. Let ``shape`` be a temporary list of length ``N`` for storing the shape of the result array. + +#. Let ``i`` be ``N-1``. + +#. Repeat, while ``i >= 0`` + + #. Let ``n1`` be ``N1 - N + i``. + + #. If ``n1 >= 0``, let ``d1`` be the size of dimension ``n1`` for array ``A`` (i.e., the result of ``shape1[n1]``); else, let ``d1`` be ``1``. + + #. Let ``n2`` be ``N2 - N + i``. + + #. If ``n2 >= 0``, let ``d2`` be the size of dimension ``n2`` for array ``B`` (i.e., the result of ``shape2[n2]``); else, let ``d2`` be ``1``. + + #. If ``d1 == 1``, then set the ``i``\th element of ``shape`` to ``d2``. + + #. Else, if ``d2 == 1``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, if ``d1 == d2``, then + + - set the ``i``\th element of ``shape`` to ``d1``. + + #. Else, throw an exception. + + #. Set ``i`` to ``i-1``. + +#. Let ``tuple(shape)`` be the shape of the result array. + +Examples +~~~~~~~~ + +The following examples demonstrate the application of the broadcasting algorithm for two compatible arrays. + +:: + + A (4d array): 8 x 1 x 6 x 1 + B (3d array): 7 x 1 x 5 + --------------------------------- + Result (4d array): 8 x 7 x 6 x 5 + A (2d array): 5 x 4 + B (1d array): 1 + ------------------------- + Result (2d array): 5 x 4 + A (2d array): 5 x 4 + B (1d array): 4 + ------------------------- + Result (2d array): 5 x 4 + A (3d array): 15 x 3 x 5 + B (3d array): 15 x 1 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 5 + ------------------------------ + Result (3d array): 15 x 3 x 5 + A (3d array): 15 x 3 x 5 + B (2d array): 3 x 1 + ------------------------------ + Result (3d array): 15 x 3 x 5 + + +The following examples demonstrate array shapes which do **not** broadcast. + +:: + + A (1d array): 3 + B (1d array): 4 # dimension does not match + + A (2d array): 2 x 1 + B (3d array): 8 x 4 x 3 # second dimension does not match + + A (3d array): 15 x 3 x 5 + B (2d array): 15 x 3 # singleton dimensions can only be prepended, not appended + +In-place Semantics +------------------ + +As implied by the broadcasting algorithm, in-place element-wise operations (including ``__setitem__``) must not change the shape of the in-place array as a result of broadcasting. Such operations should only be supported in the case where the right-hand operand can broadcast to the shape of the left-hand operand, after any indexing operations are performed. + +For example: + +:: + + x = empty((2, 3, 4)) + a = empty((1, 3, 4)) + + # This is OK. The shape of a, (1, 3, 4), can broadcast to the shape of x[...], (2, 3, 4) + x[...] = a + + # This is not allowed. The shape of a, (1, 3, 4), can NOT broadcast to the shape of x[1, ...], (3, 4) + x[1, ...] = a diff --git a/spec/2024.12/API_specification/constants.rst b/spec/2024.12/API_specification/constants.rst new file mode 100644 index 000000000..71cb8688d --- /dev/null +++ b/spec/2024.12/API_specification/constants.rst @@ -0,0 +1,26 @@ +Constants +========= + + Array API specification for constants. + +A conforming implementation of the array API standard must provide and support the following constants adhering to the following conventions. + +- Each constant must have a Python floating-point data type (i.e., ``float``) and be provided as a Python scalar value. + +Objects in API +-------------- + +.. currentmodule:: array_api.constants + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + + e + inf + nan + newaxis + pi diff --git a/spec/2024.12/API_specification/creation_functions.rst b/spec/2024.12/API_specification/creation_functions.rst new file mode 100644 index 000000000..ff5c06368 --- /dev/null +++ b/spec/2024.12/API_specification/creation_functions.rst @@ -0,0 +1,36 @@ +Creation Functions +================== + + Array API specification for creating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + arange + asarray + empty + empty_like + eye + from_dlpack + full + full_like + linspace + meshgrid + ones + ones_like + tril + triu + zeros + zeros_like diff --git a/spec/2024.12/API_specification/data_type_functions.rst b/spec/2024.12/API_specification/data_type_functions.rst new file mode 100644 index 000000000..d42968c7b --- /dev/null +++ b/spec/2024.12/API_specification/data_type_functions.rst @@ -0,0 +1,26 @@ +Data Type Functions +=================== + + Array API specification for data type functions. + +A conforming implementation of the array API standard must provide and support the following data type functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + astype + can_cast + finfo + iinfo + isdtype + result_type diff --git a/spec/2024.12/API_specification/data_types.rst b/spec/2024.12/API_specification/data_types.rst new file mode 100644 index 000000000..5987dd322 --- /dev/null +++ b/spec/2024.12/API_specification/data_types.rst @@ -0,0 +1,143 @@ +.. _data-types: + +Data Types +========== + + Array API specification for supported data types. + +A conforming implementation of the array API standard must provide and support +the following data types ("dtypes") in its array object, and as data type +objects in its main namespace under the specified names: + ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| dtype object | description | ++==============+============================================================================================================================================================================================+ +| bool | Boolean (``True`` or ``False``). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int8 | An 8-bit signed integer whose values exist on the interval ``[-128, +127]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int16 | A 16-bit signed integer whose values exist on the interval ``[−32,767, +32,767]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int32 | A 32-bit signed integer whose values exist on the interval ``[−2,147,483,647, +2,147,483,647]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| int64 | A 64-bit signed integer whose values exist on the interval ``[−9,223,372,036,854,775,807, +9,223,372,036,854,775,807]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint8 | An 8-bit unsigned integer whose values exist on the interval ``[0, +255]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint16 | A 16-bit unsigned integer whose values exist on the interval ``[0, +65,535]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint32 | A 32-bit unsigned integer whose values exist on the interval ``[0, +4,294,967,295]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| uint64 | A 64-bit unsigned integer whose values exist on the interval ``[0, +18,446,744,073,709,551,615]``. | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float32 | IEEE 754 single-precision (32-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| float64 | IEEE 754 double-precision (64-bit) binary floating-point number (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex64 | Single-precision (64-bit) complex floating-point number whose real and imaginary components must be IEEE 754 single-precision (32-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| complex128 | Double-precision (128-bit) complex floating-point number whose real and imaginary components must be IEEE 754 double-precision (64-bit) binary floating-point numbers (see IEEE 754-2019). | ++--------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + +Data type objects must have the following methods (no attributes are required): + +.. + NOTE: please keep the functions in alphabetical order + +.. currentmodule:: array_api.data_types + +.. autosummary:: + :toctree: generated + :template: method.rst + + __eq__ + + +.. note:: + A conforming implementation of the array API standard may provide and + support additional data types beyond those described in this specification. + It may also support additional methods and attributes on dtype objects. + +.. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, subnormal behavior is left unspecified and, thus, implementation-defined. Conforming implementations may vary in their support for subnormal numbers. + + +Use of data type objects +------------------------ + +Data type objects are used as ``dtype`` specifiers in functions and methods +(e.g., ``zeros((2, 3), dtype=float32)``), accessible as ``.dtype`` attribute on +arrays, and used in various casting and introspection functions (e.g., +``isdtype(x.dtype, 'integral')``). + +``dtype`` keywords in functions specify the data type of arrays returned from +functions or methods. ``dtype`` keywords are not required to affect the data +type used for intermediate calculations or results (e.g., implementors are free +to use a higher-precision data type when accumulating values for reductions, as +long as the returned array has the specified data type). + +.. note:: + Implementations may provide other ways to specify data types (e.g., ``zeros((2, 3), dtype='f4')``) which are not described in this specification; however, in order to ensure portability, array library consumers are recommended to use data type objects as provided by specification conforming array libraries. + +See :ref:`type-promotion` for specification guidance describing the rules governing the interaction of two or more data types or data type objects. + + +.. _data-type-defaults: + +Default Data Types +------------------ + +A conforming implementation of the array API standard must define the following default data types. + +- a default real-valued floating-point data type (either ``float32`` or ``float64``). +- a default complex floating-point data type (either ``complex64`` or ``complex128``). +- a default integer data type (either ``int32`` or ``int64``). +- a default array index data type (either ``int32`` or ``int64``). + +The default real-valued floating-point and complex floating-point data types must be the same across platforms. + +The default complex floating-point point data type should match the default real-valued floating-point data type. For example, if the default real-valued floating-point data type is ``float32``, the default complex floating-point data type must be ``complex64``. If the default real-valued floating-point data type is ``float64``, the default complex floating-point data type must be ``complex128``. + +The default integer data type should be the same across platforms, but the default may vary depending on whether Python is 32-bit or 64-bit. + +The default array index data type may be ``int32`` on 32-bit platforms, but the default should be ``int64`` otherwise. + +Note that it is possible that a library supports multiple devices, with not all +those device types supporting the same data types. In this case, the default +integer or floating-point data types may vary with device. If that is the case, +the library should clearly warn about this in its documentation. + +.. note:: + The default data types should be clearly defined in a conforming library's documentation. + + +.. _data-type-categories: + +Data Type Categories +-------------------- + +For the purpose of organizing functions within this specification, the following data type categories are defined. + ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| data type category | dtypes | ++============================+========================================================================================================================================================+ +| Numeric | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, ``uint64``, ``float32``, and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Integer | ``int8``, ``int16``, ``int32``, ``int64``, ``uint8``, ``uint16``, ``uint32``, and ``uint64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Floating-point | ``float32``, ``float64``, ``complex64``, and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Real-valued floating-point | ``float32`` and ``float64``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Complex floating-point | ``complex64`` and ``complex128``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Boolean | ``bool``. | ++----------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +.. note:: + Conforming libraries are not required to organize data types according to these categories. These categories are only intended for use within this specification. diff --git a/spec/2024.12/API_specification/elementwise_functions.rst b/spec/2024.12/API_specification/elementwise_functions.rst new file mode 100644 index 000000000..9758c68db --- /dev/null +++ b/spec/2024.12/API_specification/elementwise_functions.rst @@ -0,0 +1,86 @@ +.. _element-wise-functions: + +Element-wise Functions +====================== + + Array API specification for element-wise functions. + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + abs + acos + acosh + add + asin + asinh + atan + atan2 + atanh + bitwise_and + bitwise_left_shift + bitwise_invert + bitwise_or + bitwise_right_shift + bitwise_xor + ceil + clip + conj + copysign + cos + cosh + divide + equal + exp + expm1 + floor + floor_divide + greater + greater_equal + hypot + imag + isfinite + isinf + isnan + less + less_equal + log + log1p + log2 + log10 + logaddexp + logical_and + logical_not + logical_or + logical_xor + maximum + minimum + multiply + negative + nextafter + not_equal + positive + pow + real + reciprocal + remainder + round + sign + signbit + sin + sinh + square + sqrt + subtract + tan + tanh + trunc diff --git a/spec/2024.12/API_specification/function_and_method_signatures.rst b/spec/2024.12/API_specification/function_and_method_signatures.rst new file mode 100644 index 000000000..0eca2ac69 --- /dev/null +++ b/spec/2024.12/API_specification/function_and_method_signatures.rst @@ -0,0 +1,63 @@ +.. _function-and-method-signatures: + +Function and method signatures +============================== + +Function signatures in this standard adhere to the following: + +1. Positional parameters should 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. + + *Rationale: existing libraries have incompatible conventions, and using names + of positional parameters is not normal/recommended practice.* + + .. note:: + + Positional-only parameters are only available in Python >= 3.8. Libraries + still supporting 3.7 or 3.6 may consider making the API standard-compliant + namespace >= 3.8. Alternatively, they can add guidance to their users in the + documentation to use the functions as if they were positional-only. + +2. Optional parameters should be `keyword-only `_ arguments. + + *Rationale: this leads to more readable code, and it makes it easier to + evolve an API over time by adding keywords without having to worry about + keyword order.* + +3. For functions that have a single positional array parameter, that parameter + is called ``x``. For functions that have multiple array parameters, those + parameters are called ``xi`` with ``i = 1, 2, ...`` (i.e., ``x1``, ``x2``). + +4. Signatures include type annotations. The type annotations are also added to + individual parameter and return value descriptions. For code which aims to + adhere to the standard, adding type annotations is strongly recommended. + +A function signature and description will look like: + +:: + + funcname(x1, x2, /, *, key1=-1, key2=None) -> out: + Parameters + + x1 : array + description + x2 : array + description + key1 : int + description + key2 : Optional[str] + description + + Returns + + out : array + description + + +Method signatures will follow the same conventions modulo the addition of ``self``. + +Note that there are a few exceptions to rules (1) and (2), in cases where +it enhances readability or use of the non-default form of the parameter in +question is commonly used in code written for existing array libraries. diff --git a/spec/2024.12/API_specification/index.rst b/spec/2024.12/API_specification/index.rst new file mode 100644 index 000000000..ffc3d3775 --- /dev/null +++ b/spec/2024.12/API_specification/index.rst @@ -0,0 +1,41 @@ +.. _api-specification: + +API specification +================= + +A conforming implementation of the array API standard must provide and support the APIs and behavior detailed in this specification while adhering to the following conventions. + +- When a function signature includes a `/`, positional parameters must be `positional-only `_ parameters. See :ref:`function-and-method-signatures`. +- When a function signature includes a `*`, optional parameters must be `keyword-only `_ arguments. See :ref:`function-and-method-signatures`. +- Broadcasting semantics must follow the semantics defined in :ref:`broadcasting`. +- Unless stated otherwise, functions must support the data types defined in :ref:`data-types`. +- Functions may only be required for a subset of input data types. Libraries may choose to implement functions for additional data types, but that behavior is not required by the specification. See :ref:`data-type-categories`. +- Unless stated otherwise, functions must adhere to the type promotion rules defined in :ref:`type-promotion`. +- Unless stated otherwise, floating-point operations must adhere to IEEE 754-2019. +- Unless stated otherwise, element-wise mathematical functions must satisfy the minimum accuracy requirements defined in :ref:`accuracy`. + + +.. toctree:: + :caption: API specification + :maxdepth: 3 + + array_object + broadcasting + constants + creation_functions + data_type_functions + data_types + elementwise_functions + function_and_method_signatures + indexing + indexing_functions + inspection + linear_algebra_functions + manipulation_functions + searching_functions + set_functions + sorting_functions + statistical_functions + type_promotion + utility_functions + version diff --git a/spec/2024.12/API_specification/indexing.rst b/spec/2024.12/API_specification/indexing.rst new file mode 100644 index 000000000..058003c51 --- /dev/null +++ b/spec/2024.12/API_specification/indexing.rst @@ -0,0 +1,253 @@ +.. _indexing: + +Indexing +======== + + Array API specification for indexing arrays. + +A conforming implementation of the array API standard must adhere to the following conventions. + + +.. _indexing-single-axis: + +Single-axis Indexing +-------------------- + +To index a single array axis, an array must support standard Python indexing rules. Let ``n`` be the axis (dimension) size. + +- An integer index must be an object satisfying `operator.index `_ (e.g., ``int``). + +- Nonnegative indices must start at ``0`` (i.e., zero-based indexing). + +- **Valid** nonnegative indices must reside on the half-open interval ``[0, n)``. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- Negative indices must count backward from the last array index, starting from ``-1`` (i.e., negative-one-based indexing, where ``-1`` refers to the last array index). + + .. note:: + A negative index ``j`` is equivalent to ``n-j``; the former is syntactic sugar for the latter, providing a shorthand for indexing elements that would otherwise need to be specified in terms of the axis (dimension) size. + +- **Valid** negative indices must reside on the closed interval ``[-n, -1]``. + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- A negative index ``j`` is related to a zero-based nonnegative index ``i`` via ``i = n+j``. + +- Colons ``:`` must be used for `slices `_: ``start:stop:step``, where ``start`` is inclusive and ``stop`` is exclusive. + + .. note:: + The specification does not support returning scalar (i.e., non-array) values from operations, including indexing. In contrast to standard Python indexing rules, for any index, or combination of indices, which select a single value, the result must be a zero-dimensional array containing the selected value. + +Slice Syntax +~~~~~~~~~~~~ + +The basic slice syntax is ``i:j:k`` where ``i`` is the starting index, ``j`` is the stopping index, and ``k`` is the step (``k != 0``). A slice may contain either one or two colons, with either an integer value or nothing on either side of each colon. The following are valid slices. + +:: + + A[:] + A[i:] + A[:j] + A[i:k] + A[::] + A[i::] + A[:j:] + A[::k] + A[i:j:] + A[i::k] + A[:j:k] + A[i::k] + A[i:j:k] + +.. note:: + Slice syntax can be equivalently achieved using the Python built-in `slice() `_ API. From the perspective of ``A``, the behavior of ``A[i:j:k]`` and ``A[slice(i, j, k)]`` is indistinguishable (i.e., both retrieve the same set of items from ``__getitem__``). + +Using a slice to index a single array axis must select ``m`` elements with index values + +:: + + i, i+k, i+2k, i+3k, ..., i+(m-1)k + +where + +:: + + m = q + r + +and ``q`` and ``r`` (``r != 0``) are the quotient and remainder obtained by dividing ``j-i`` by ``k`` + +:: + + j - i = qk + r + +such that + +:: + + j > i + (m-1)k + +.. note:: + For ``i`` on the interval ``[0, n)`` (where ``n`` is the axis size), ``j`` on the interval ``(0, n]``, ``i`` less than ``j``, and positive step ``k``, a starting index ``i`` is **always** included, while the stopping index ``j`` is **always** excluded. This preserves ``x[:i]+x[i:]`` always being equal to ``x``. + +.. note:: + Using a slice to index into a single array axis should select the same elements as using a slice to index a Python list of the same size. + +Slice syntax must have the following defaults. Let ``n`` be the axis (dimension) size. + +- If ``k`` is not provided (e.g., ``0:10``), ``k`` must equal ``1``. +- If ``k`` is greater than ``0`` and ``i`` is not provided (e.g., ``:10:2``), ``i`` must equal ``0``. +- If ``k`` is greater than ``0`` and ``j`` is not provided (e.g., ``0::2``), ``j`` must equal ``n``. +- If ``k`` is less than ``0`` and ``i`` is not provided (e.g., ``:10:-2``), ``i`` must equal ``n-1``. +- If ``k`` is less than ``0`` and ``j`` is not provided (e.g., ``0::-2``), ``j`` must equal ``-n-1``. + +Using a slice to index a single array axis must adhere to the following rules. Let ``n`` be the axis (dimension) size. + +- If ``i`` equals ``j``, a slice must return an empty array, whose axis (dimension) size along the indexed axis is ``0``. + +- Indexing via ``:`` and ``::`` must be equivalent and have defaults derived from the rules above. Both ``:`` and ``::`` indicate to select all elements along a single axis (dimension). + + .. note:: + This specification does not require "clipping" out-of-bounds slice indices. This is in contrast to Python slice semantics where ``0:100`` and ``0:10`` are equivalent on a list of length ``10``. + +The following ranges for the start and stop values of a slice must be supported. Let ``n`` be the axis (dimension) size being sliced. For a slice ``i:j:k``, the behavior specified above should be implemented for the following: + +- ``i`` or ``j`` omitted (``None``). +- ``-n <= i <= n``. +- For ``k > 0`` or ``k`` omitted (``None``), ``-n <= j <= n``. +- For ``k < 0``, ``-n - 1 <= j <= max(0, n - 1)``. + +The behavior outside of these bounds is unspecified. + +.. note:: + *Rationale: this is consistent with bounds checking for integer indexing; the behavior of out-of-bounds indices is left unspecified. Implementations may choose to clip (consistent with Python* ``list`` *slicing semantics), raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + + +.. _indexing-multi-axis: + +Multi-axis Indexing +------------------- + +Multi-dimensional arrays must extend the concept of single-axis indexing to multiple axes by applying single-axis indexing rules along each axis (dimension) and supporting the following additional rules. Let ``N`` be the number of dimensions ("rank") of a multi-dimensional array ``A``. + +- Each axis may be independently indexed via single-axis indexing by providing a comma-separated sequence ("selection tuple") of single-axis indexing expressions (e.g., ``A[:, 2:10, :, 5]``). + + .. note:: + In Python, ``A[(exp1, exp2, ..., expN)]`` is equivalent to ``A[exp1, exp2, ..., expN]``; the latter is syntactic sugar for the former. + + Accordingly, if ``A`` has rank ``1``, then ``A[(2:10,)]`` must be equivalent to ``A[2:10]``. If ``A`` has rank ``2``, then ``A[(2:10, :)]`` must be equivalent to ``A[2:10, :]``. And so on and so forth. + +- Providing a single nonnegative integer ``i`` as a single-axis index must index the same elements as the slice ``i:i+1``. + +- Providing a single negative integer ``i`` as a single-axis index must index the same elements as the slice ``n+i:n+i+1``, where ``n`` is the axis (dimension) size. + +- Providing a single integer as a single-axis index must reduce the number of array dimensions by ``1`` (i.e., the array rank must decrease by one; if ``A`` has rank ``2``, ``rank(A)-1 == rank(A[0, :])``). In particular, a selection tuple with the ``m``\th element an integer (and all other entries ``:``) indexes a sub-array with rank ``N-1``. + + .. note:: + When providing a single integer as a single-axis index to an array of rank ``1``, the result should be an array of rank ``0``, not a NumPy scalar. Note that this behavior differs from NumPy. + +- Providing a slice must retain array dimensions (i.e., the array rank must remain the same; ``rank(A) == rank(A[:])``). + +- Providing `ellipsis `_ must apply ``:`` to each dimension necessary to index all dimensions (e.g., if ``A`` has rank ``4``, ``A[1:, ..., 2:5] == A[1:, :, :, 2:5]``). Only a single ellipsis must be allowed. An ``IndexError`` exception must be raised if more than one ellipsis is provided. + +- Providing an empty tuple or an ellipsis to an array of rank ``0`` must result in an array of the same rank (i.e., if ``A`` has rank ``0``, ``A == A[()]`` and ``A == A[...]``). + + .. note:: + This behavior differs from NumPy where providing an empty tuple to an array of rank ``0`` returns a NumPy scalar. + +- Each ``None`` in the selection tuple must expand the dimensions of the resulting selection by one dimension of size ``1``. The position of the added dimension must be the same as the position of ``None`` in the selection tuple. + + .. note:: + Expanding dimensions can be equivalently achieved via repeated invocation of :func:`~array_api.expand_dims`. + + .. note:: + The constant ``newaxis`` is an alias of ``None`` and can thus be used in a similar manner as ``None``. + +- Except in the case of providing a single ellipsis (e.g., ``A[2:10, ...]`` or ``A[1:, ..., 2:5]``), the number of provided single-axis indexing expressions (excluding ``None``) should equal ``N``. For example, if ``A`` has rank ``2``, a single-axis indexing expression should be explicitly provided for both axes (e.g., ``A[2:10, :]``). An ``IndexError`` exception should be raised if the number of provided single-axis indexing expressions (excluding ``None``) is less than ``N``. + + .. note:: + Some libraries, such as SymPy, support flat indexing (i.e., providing a single-axis indexing expression to a higher-dimensional array). That practice is not supported here. + + To perform flat indexing, use ``reshape(x, (-1,))[integer]``. + +- An ``IndexError`` exception must be raised if the number of provided single-axis indexing expressions (excluding ``None``) is greater than ``N``. + + .. note:: + This specification leaves unspecified the behavior of providing a slice which attempts to select elements along a particular axis, but whose starting index is out-of-bounds. + + *Rationale: this is consistent with bounds-checking for single-axis indexing. An implementation may choose to set the axis (dimension) size of the result array to* ``0`` *, raise an exception, return junk values, or some other behavior depending on device requirements and performance considerations.* + +Integer Array Indexing +---------------------- + +.. note:: + Integer array indexing, as described in this specification, is a reduced subset of "vectorized indexing" semantics, as implemented in libraries such as NumPy. In vectorized indexing, integers and integer arrays are broadcasted to integer arrays having a common shape before being "zipped" together to form a list of index coordinates. This form of indexing diverges from the multi-axis indexing semantics described above (see :ref:`indexing-multi-axis`) where each element of an indexing tuple comprised of integers and slices independently indexes a particular axis. This latter form of indexing is commonly referred to as "orthogonal indexing" and is the default form of indexing outside of Python in languages such as Julia and MATLAB. + +An array must support indexing by an indexing tuple which contains only integers and integer arrays according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S1``. Let ``T`` be a tuple ``(t1, t2, ..., tN)`` having length ``N``. Let ``tk`` be an individual element of ``T``. + +.. note:: + This specification does not currently address indexing tuples which combine slices and integer arrays. Behavior for such indexing tuples is left unspecified and thus implementation-defined. This may be revisited in a future revision of this standard. + +.. note:: + This specification does not currently address indexing tuples which include array-like elements, such as Python lists, tuples, and other sequences. Behavior when indexing an array using array-like elements is left unspecified and thus implementation-defined. + +- If ``tk`` is an integer array, ``tk`` should have the default array index data type (see :ref:`data-type-defaults`). + +.. note:: + Conforming implementations of this standard may support integer arrays having other integer data types; however, consumers of this standard should be aware that integer arrays having uncommon array index data types such as ``int8`` and ``uint8`` may not be widely supported as index arrays across conforming array libraries. To dynamically resolve the default array index data type, including for that of the current device context, use the inspection API ``default_dtypes()``. + +- Providing a zero-dimensional integer array ``tk`` containing an integer index must be equivalent to providing an integer index having the value ``int(tk)``. Conversely, each integer index ``tk`` must be equivalent to a zero-dimensional integer array containing the same value and be treated as such, including shape inference and broadcasting. Accordingly, if ``T`` consists of only integers and zero-dimensional integer arrays, the result must be equivalent to indexing multiple axes using integer indices. For example, if ``A`` is a two-dimensional array, ``T`` is the tuple ``(i, J)``, ``i`` is a valid integer index, and ``J`` is a zero-dimensional array containing a valid integer index ``j``, the result of ``A[T]`` must be equivalent to ``A[(i,j)]`` (see :ref:`indexing-multi-axis`). + +- If ``tk`` is an integer array, each element in ``tk`` must independently satisfy the rules stated above for indexing a single-axis with an integer index (see :ref:`indexing-single-axis`). + + .. note:: + This specification does not require bounds checking. The behavior for out-of-bounds integer indices is left unspecified. + +- If ``tk`` is an integer array containing duplicate valid integer indices, the result must include the corresponding elements of ``A`` with the same duplication. + + .. + TODO: once setitem semantics are determined, insert the following note: Given the assignment operation ``x[T] = y[...]``, if ``T`` contains an integer array having duplicate indices, the order in which elements in ``y`` are assigned to the corresponding element(s) in ``x`` is unspecified and thus implementation-defined. + +- If ``T`` contains at least one non-zero-dimensional integer array, all elements of ``T`` must be broadcast against each other to determine a common shape ``S2 = (s1, s2, ..., sN)`` according to standard broadcasting rules (see :ref:`broadcasting`). If one or more elements in ``T`` are not broadcast-compatible with the others, an exception must be raised. + +- After broadcasting elements of ``T`` to a common shape ``S2``, the resulting tuple ``U = (u1, u2, ..., uN)`` must only contain integer arrays having shape ``S2`` (i.e., ``u1 = broadcast_to(t1, S2)``, ``u2 = broadcast_to(t2, S2)``, et cetera). + +- Each element in ``U`` must specify a multi-dimensional index ``v_i = (u1[i], u2[i], ..., uN[i])``, where ``i`` ranges over ``S2``. The result of ``A[U]`` must be constructed by gathering elements from ``A`` at each coordinate tuple ``v_i``. For example, let ``A`` have shape ``(4,4)`` and ``U`` contain integer arrays equivalent to ``([0,1], [2,3])``, with ``u1 = [0,1]`` and ``u2 = [2,3]``. The resulting coordinate tuples must be ``(0,2)`` and ``(1,3)``, respectively, and the resulting array must have shape ``(2,)`` and contain elements ``A[(0,2)]`` and ``A[(1,3)]``. + +- The result of ``A[U]`` must be an array having the broadcasted shape ``S2``. + +Boolean Array Indexing +---------------------- + +.. admonition:: Data-dependent output shape + :class: admonition important + + For common boolean array use cases (e.g., using a dynamically-sized boolean array mask to filter the values of another array), the shape of the output array is data-dependent; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find boolean array indexing difficult to implement. Accordingly, such libraries may choose to omit boolean array indexing. See :ref:`data-dependent-output-shapes` section for more details. + +An array must support indexing where the **sole index** is an ``M``-dimensional boolean array ``B`` with shape ``S1 = (s1, ..., sM)`` according to the following rules. Let ``A`` be an ``N``-dimensional array with shape ``S2 = (s1, ..., sM, ..., sN)``. + + .. note:: + The prohibition against combining boolean array indices with other single-axis indexing expressions includes the use of ``None``. To expand dimensions of the returned array, use repeated invocation of :func:`~array_api.expand_dims`. + +- If ``N >= M``, then ``A[B]`` must replace the first ``M`` dimensions of ``A`` with a single dimension having a size equal to the number of ``True`` elements in ``B``. The values in the resulting array must be in row-major (C-style order); this is equivalent to ``A[nonzero(B)]``. + + .. note:: + For example, if ``N == M == 2``, indexing ``A`` via a boolean array ``B`` will return a one-dimensional array whose size is equal to the number of ``True`` elements in ``B``. + +- If ``N < M``, then an ``IndexError`` exception must be raised. + +- The size of each dimension in ``B`` must equal the size of the corresponding dimension in ``A`` or be ``0``, beginning with the first dimension in ``A``. If a dimension size does not equal the size of the corresponding dimension in ``A`` and is not ``0``, then an ``IndexError`` exception must be raised. + +- The elements of a boolean index array must be iterated in row-major, C-style order, with the exception of zero-dimensional boolean arrays. + +- A zero-dimensional boolean index array (equivalent to ``True`` or ``False``) must follow the same axis replacement rules stated above. Namely, a zero-dimensional boolean index array removes zero dimensions and adds a single dimension of length ``1`` if the index array's value is ``True`` and of length ``0`` if the index array's value is ``False``. Accordingly, for a zero-dimensional boolean index array ``B``, the result of ``A[B]`` has shape ``S = (1, s1, ..., sN)`` if the index array's value is ``True`` and has shape ``S = (0, s1, ..., sN)`` if the index array's value is ``False``. + +Return Values +------------- + +The result of an indexing operation (e.g., multi-axis indexing, boolean array indexing, etc) must be an array of the same data type as the indexed array. + +.. note:: + The specified return value behavior includes indexing operations which return a single value (e.g., accessing a single element within a one-dimensional array). diff --git a/spec/2024.12/API_specification/indexing_functions.rst b/spec/2024.12/API_specification/indexing_functions.rst new file mode 100644 index 000000000..c13e55ecf --- /dev/null +++ b/spec/2024.12/API_specification/indexing_functions.rst @@ -0,0 +1,24 @@ +.. _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. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + take + take_along_axis diff --git a/spec/2024.12/API_specification/inspection.rst b/spec/2024.12/API_specification/inspection.rst new file mode 100644 index 000000000..89d9c602a --- /dev/null +++ b/spec/2024.12/API_specification/inspection.rst @@ -0,0 +1,42 @@ +.. _inspection: + +Inspection +========== + + Array API specification for namespace inspection utilities. + +A conforming implementation of the array API standard must provide and support the following functions and associated inspection APIs. + + +Objects in API +-------------- + +.. currentmodule:: array_api.info + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + __array_namespace_info__ + + +Inspection APIs +--------------- + +In the namespace (or class) returned by ``__array_namespace_info__``, a conforming implementation of the array API standard must provide and support the following functions (or methods) for programmatically querying data type and device support, capabilities, and other specification-defined implementation-specific behavior, as documented in the functions described below. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + capabilities + default_device + default_dtypes + devices + dtypes diff --git a/spec/2024.12/API_specification/linear_algebra_functions.rst b/spec/2024.12/API_specification/linear_algebra_functions.rst new file mode 100644 index 000000000..04d36f50a --- /dev/null +++ b/spec/2024.12/API_specification/linear_algebra_functions.rst @@ -0,0 +1,23 @@ +Linear Algebra Functions +======================== + + Array API specification for linear algebra functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + matmul + matrix_transpose + tensordot + vecdot diff --git a/spec/2024.12/API_specification/manipulation_functions.rst b/spec/2024.12/API_specification/manipulation_functions.rst new file mode 100644 index 000000000..395c1c3e2 --- /dev/null +++ b/spec/2024.12/API_specification/manipulation_functions.rst @@ -0,0 +1,34 @@ +Manipulation Functions +====================== + + Array API specification for manipulating arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + broadcast_arrays + broadcast_to + concat + expand_dims + flip + moveaxis + permute_dims + repeat + reshape + roll + squeeze + stack + tile + unstack diff --git a/spec/2024.12/API_specification/searching_functions.rst b/spec/2024.12/API_specification/searching_functions.rst new file mode 100644 index 000000000..1a584f158 --- /dev/null +++ b/spec/2024.12/API_specification/searching_functions.rst @@ -0,0 +1,28 @@ +.. _searching-functions: + +Searching Functions +=================== + + Array API specification for functions for searching arrays. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argmax + argmin + count_nonzero + nonzero + searchsorted + where diff --git a/spec/2024.12/API_specification/set_functions.rst b/spec/2024.12/API_specification/set_functions.rst new file mode 100644 index 000000000..addf31e1f --- /dev/null +++ b/spec/2024.12/API_specification/set_functions.rst @@ -0,0 +1,24 @@ +Set Functions +============= + + Array API specification for creating and operating on sets. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + unique_all + unique_counts + unique_inverse + unique_values diff --git a/spec/2024.12/API_specification/sorting_functions.rst b/spec/2024.12/API_specification/sorting_functions.rst new file mode 100644 index 000000000..ad3af8857 --- /dev/null +++ b/spec/2024.12/API_specification/sorting_functions.rst @@ -0,0 +1,31 @@ +Sorting Functions +================= + + Array API specification for sorting functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +.. note:: + + For floating-point input arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. + + Implementations may choose to sort signed zeros (``-0 < +0``) or may choose to rely solely on value equality (``==``). + + Implementations may choose to sort NaNs (e.g., to the end or to the beginning of a returned array) or leave them in-place. Should an implementation sort NaNs, the sorting convention should be clearly documented in the conforming implementation's documentation. + + While defining a sort order for IEEE 754 floating-point numbers is recommended in order to facilitate reproducible and consistent sort results, doing so is not currently required by this specification. + +.. currentmodule:: array_api + +Objects in API +-------------- +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + argsort + sort diff --git a/spec/2024.12/API_specification/statistical_functions.rst b/spec/2024.12/API_specification/statistical_functions.rst new file mode 100644 index 000000000..eb5e1a5d6 --- /dev/null +++ b/spec/2024.12/API_specification/statistical_functions.rst @@ -0,0 +1,29 @@ +Statistical Functions +===================== + + Array API specification for statistical functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cumulative_prod + cumulative_sum + max + mean + min + prod + std + sum + var diff --git a/spec/2024.12/API_specification/type_promotion.rst b/spec/2024.12/API_specification/type_promotion.rst new file mode 100644 index 000000000..7a82c763b --- /dev/null +++ b/spec/2024.12/API_specification/type_promotion.rst @@ -0,0 +1,163 @@ +.. _type-promotion: + +Type Promotion Rules +==================== + + Array API specification for type promotion rules. + +Type promotion rules can be understood at a high level from the following diagram: + +.. image:: ../../_static/images/dtype_promotion_lattice.png + :target: Type promotion diagram + +*Type promotion diagram. Promotion between any two types is given by their join on this lattice. Only the types of participating arrays matter, not their values. Dashed lines indicate that behavior for Python scalars is undefined on overflow. Boolean, integer and floating-point dtypes are not connected, indicating mixed-kind promotion is undefined.* + +Rules +----- + +A conforming implementation of the array API standard must implement the following type promotion rules governing the common result type for two **array** operands during an arithmetic operation. + +A conforming implementation of the array API standard may support additional type promotion rules beyond those described in this specification. + +.. note:: + Type codes are used here to keep tables readable; they are not part of the standard. In code, use the data type objects specified in :ref:`data-types` (e.g., ``int16`` rather than ``'i2'``). + +.. + Note: please keep table columns aligned + +The following type promotion tables specify the casting behavior for operations involving two array operands. When more than two array operands participate, application of the promotion tables is associative (i.e., the result does not depend on operand order). + +Signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | i1 | i2 | i4 | i8 | ++========+====+====+====+====+ +| **i1** | i1 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i2** | i2 | i2 | i4 | i8 | ++--------+----+----+----+----+ +| **i4** | i4 | i4 | i4 | i8 | ++--------+----+----+----+----+ +| **i8** | i8 | i8 | i8 | i8 | ++--------+----+----+----+----+ + +where + +- **i1**: 8-bit signed integer (i.e., ``int8``) +- **i2**: 16-bit signed integer (i.e., ``int16``) +- **i4**: 32-bit signed integer (i.e., ``int32``) +- **i8**: 64-bit signed integer (i.e., ``int64``) + +Unsigned integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+----+ +| | u1 | u2 | u4 | u8 | ++========+====+====+====+====+ +| **u1** | u1 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u2** | u2 | u2 | u4 | u8 | ++--------+----+----+----+----+ +| **u4** | u4 | u4 | u4 | u8 | ++--------+----+----+----+----+ +| **u8** | u8 | u8 | u8 | u8 | ++--------+----+----+----+----+ + +where + +- **u1**: 8-bit unsigned integer (i.e., ``uint8``) +- **u2**: 16-bit unsigned integer (i.e., ``uint16``) +- **u4**: 32-bit unsigned integer (i.e., ``uint32``) +- **u8**: 64-bit unsigned integer (i.e., ``uint64``) + +Mixed unsigned and signed integer type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++--------+----+----+----+ +| | u1 | u2 | u4 | ++========+====+====+====+ +| **i1** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i2** | i2 | i4 | i8 | ++--------+----+----+----+ +| **i4** | i4 | i4 | i8 | ++--------+----+----+----+ +| **i8** | i8 | i8 | i8 | ++--------+----+----+----+ + +Floating-point type promotion table +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ++---------+-----+-----+-----+-----+ +| | f4 | f8 | c8 | c16 | ++=========+=====+=====+=====+=====+ +| **f4** | f4 | f8 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **f8** | f8 | f8 | c16 | c16 | ++---------+-----+-----+-----+-----+ +| **c8** | c8 | c16 | c8 | c16 | ++---------+-----+-----+-----+-----+ +| **c16** | c16 | c16 | c16 | c16 | ++---------+-----+-----+-----+-----+ + +where + +- **f4**: single-precision (32-bit) floating-point number (i.e., ``float32``) +- **f8**: double-precision (64-bit) floating-point number (i.e., ``float64``) +- **c8**: single-precision complex floating-point number (i.e., ``complex64``) + composed of two single-precision (32-bit) floating-point numbers +- **c16**: double-precision complex floating-point number (i.e., ``complex128``) + composed of two double-precision (64-bit) floating-point numbers + +Notes +~~~~~ + +- Type promotion rules must apply when determining the common result type for two **array** operands during an arithmetic operation, regardless of array dimension. Accordingly, zero-dimensional arrays must be subject to the same type promotion rules as dimensional arrays. +- Type promotion of non-numerical data types to numerical data types is unspecified (e.g., ``bool`` to ``intxx`` or ``floatxx``). + +.. note:: + Mixed integer and floating-point type promotion rules are not specified because behavior varies between implementations. + + +.. _mixing-scalars-and-arrays: + +Mixing arrays with Python scalars +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Using Python scalars (i.e., instances of ``bool``, ``int``, ``float``, ``complex``) together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with the array data type: + +- a Python ``bool`` for a ``bool`` array data type. +- a Python ``int`` within the bounds of the given data type for integer array :ref:`data-types`. +- a Python ``int`` or ``float`` for real-valued floating-point array data types. +- a Python ``int``, ``float``, or ``complex`` for complex floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to a zero-dimensional array with the same data type as that of the array used in the expression. +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +Additionally, using Python ``complex`` scalars together with arrays must be supported for: + +- ``array scalar`` +- ``scalar array`` + +where ```` is a built-in operator (including in-place operators, but excluding the matmul ``@`` operator; see :ref:`operators` for operators supported by the array object) and ``scalar`` has a type and value compatible with a promoted array data type: + +- a Python ``complex`` for real-valued floating-point array data types. + +Provided the above requirements are met, the expected behavior is equivalent to: + +1. Convert the scalar to a zero-dimensional array with a complex floating-point array data type having the same precision as that of the array operand used in the expression (e.g., if an array has a ``float32`` data type, the scalar must be converted to a zero-dimensional array having a ``complex64`` data type; if an array has a ``float64`` data type, the scalar must be converted to a zero-dimensional array have a ``complex128`` data type). +2. Execute the operation for ``array 0-D array`` (or ``0-D array array`` if ``scalar`` was the left-hand argument). + +Behavior is not specified for integers outside of the bounds of a given integer data type. Integers outside of bounds may result in overflow or an error. + +Behavior is not specified when mixing a Python ``float`` and an array with an integer data type; this may give ``float32``, ``float64``, or raise an exception. Behavior is implementation-specific. + +Behavior is not specified when mixing a Python ``complex`` and an array with an integer data type; this may give ``complex64``, ``complex128``, or raise an exception. Behavior is implementation-specific. diff --git a/spec/2024.12/API_specification/utility_functions.rst b/spec/2024.12/API_specification/utility_functions.rst new file mode 100644 index 000000000..a09c99f79 --- /dev/null +++ b/spec/2024.12/API_specification/utility_functions.rst @@ -0,0 +1,23 @@ +Utility Functions +================= + + Array API specification for utility functions. + +A conforming implementation of the array API standard must provide and support the following functions. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + all + any + diff diff --git a/spec/2024.12/API_specification/version.rst b/spec/2024.12/API_specification/version.rst new file mode 100644 index 000000000..346395d9a --- /dev/null +++ b/spec/2024.12/API_specification/version.rst @@ -0,0 +1,22 @@ +Version +======= + + Array API specification for versioning. + +A conforming implementation of the array API standard must provide a `__array_api_version__` attribute - see :ref:`api-versioning` for details. + + +Objects in API +-------------- + +.. currentmodule:: array_api + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: attribute.rst + :nosignatures: + + __array_api_version__ diff --git a/spec/2024.12/assumptions.md b/spec/2024.12/assumptions.md new file mode 100644 index 000000000..b11482c5a --- /dev/null +++ b/spec/2024.12/assumptions.md @@ -0,0 +1,77 @@ +(Assumptions)= + +# Assumptions + +## Hardware and software environments + +No assumptions on a specific hardware environment are made. It must be possible +to create an array library adhering to this standard that runs (efficiently) on +a variety of different hardware: CPUs with different architectures, GPUs, +distributed systems and TPUs and other emerging accelerators. + +The same applies to software environments: it must be possible to create an +array library adhering to this standard that runs efficiently independent of +what compilers, build-time or run-time execution environment, or distribution +and install method is employed. Parallel execution, JIT compilation, and +delayed (lazy) evaluation must all be possible. + +The variety of hardware and software environments puts _constraints_ on choices +made in the API standard. For example, JIT compilers may require output dtypes +of functions to be predictable from input dtypes only rather than input values. + + +(assumptions-dependencies)= + +## Dependencies + +The only dependency that's assumed in this standard is that on Python itself. +Python >= 3.8 is assumed, motivated by the use of positional-only parameters +(see [function and method signatures](API_specification/function_and_method_signatures.rst)). + +Importantly, array libraries are not assumed to be aware of each other, or of +a common array-specific layer. The [use cases](use_cases.md) do not require +such a dependency, and building and evolving an array library is easier without +such a coupling. Facilitation support of multiple array types in downstream +libraries is an important use case however, the assumed dependency structure +for that is: + +![dependency assumptions diagram](../_static/images/dependency_assumption_diagram.png) + +Array libraries may know how to interoperate with each other, for example by +constructing their own array type from that of another library or by shared +memory use of an array (see [Data interchange mechanisms](design_topics/data_interchange.rst)). +This can be done without a dependency though - only adherence to a protocol is +enough. + +Array-consuming libraries will have to depend on one or more array libraries. +That could be a "soft dependency" though, meaning retrieving an array library +namespace from array instances that are passed in, but not explicitly doing +`import arraylib_name`. + + +## Backwards compatibility + +The assumption made during creation of this standard is that libraries are +constrained by backwards compatibility guarantees to their users, and are +likely unwilling to make significant backwards-incompatible changes for the +purpose of conforming to this standard. Therefore it is assumed that the +standard will be made available in a new namespace within each library, or the +library will provide a way to retrieve a module or module-like object that +adheres to this standard. See {ref}`how-to-adopt-this-api` for more details. + + +## Production code & interactive use + +It is assumed that the primary use case is writing production code, for example +in array-consuming libraries. As a consequence, making it easy to ensure that +code is written as intended and has unambiguous semantics is preferred - and +clear exceptions must be raised otherwise. + +It is also assumed that this does not significantly detract from the +interactive user experience. However, in case existing libraries differ in +behavior, the more strict version of that behavior is typically preferred. A +good example is array inputs to functions - while NumPy accepts lists, tuples, +generators, and anything else that could be turned into an array, most other +libraries only accept their own array types. This standard follows the latter choice. +It is likely always possible to put a thin "interactive use convenience layer" +on top of a more strict behavior. diff --git a/spec/2024.12/benchmark_suite.md b/spec/2024.12/benchmark_suite.md new file mode 100644 index 000000000..41066c6a4 --- /dev/null +++ b/spec/2024.12/benchmark_suite.md @@ -0,0 +1,3 @@ +# Benchmark suite + +Adding a benchmark suite is planned in the future. diff --git a/spec/2024.12/changelog.rst b/spec/2024.12/changelog.rst new file mode 100644 index 000000000..701a3dbcd --- /dev/null +++ b/spec/2024.12/changelog.rst @@ -0,0 +1,5 @@ +Changelog per API standard version +================================== + +.. include:: ../../CHANGELOG.md + :parser: myst_parser.sphinx_ diff --git a/spec/2024.12/conf.py b/spec/2024.12/conf.py new file mode 100644 index 000000000..dfe216bb5 --- /dev/null +++ b/spec/2024.12/conf.py @@ -0,0 +1,13 @@ +import sys +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).parents[2] / "src")) + +from array_api_stubs import _2024_12 as stubs_mod +from _array_api_conf import * + +release = "2024.12" + +nav_title = html_theme_options.get("nav_title") + " {}".format(release) +html_theme_options.update({"nav_title": nav_title}) +sys.modules["array_api"] = stubs_mod diff --git a/spec/2024.12/design_topics/C_API.rst b/spec/2024.12/design_topics/C_API.rst new file mode 100644 index 000000000..6a44596b0 --- /dev/null +++ b/spec/2024.12/design_topics/C_API.rst @@ -0,0 +1,94 @@ +.. _C-API: + +C API +===== + +Use of a C API is out of scope for this array API, as mentioned in :ref:`Scope`. +There are a lot of libraries that do use such an API - in particular via Cython code +or via direct usage of the NumPy C API. When the maintainers of such libraries +want to use this array API standard to support multiple types of arrays, they +need a way to deal with that issue. This section aims to provide some guidance. + +The assumption in the rest of this section is that performance matters for the library, +and hence the goal is to make other array types work without converting to a +``numpy.ndarray`` or another particular array type. If that's not the case (e.g. for a +visualization package), then other array types can simply be handled by converting +to the supported array type. + +.. note:: + Often a zero-copy conversion to ``numpy.ndarray`` is possible, at least for CPU arrays. + If that's the case, this may be a good way to support other array types. + The main difficulty in that case will be getting the return array type right - however, + this standard does provide a Python-level API for array construction that should allow + doing this. A relevant question is if it's possible to know with + certainty that a conversion will be zero-copy. This may indeed be + possible, see :ref:`data-interchange`. + + +Example situations for C/Cython usage +------------------------------------- + +Situation 1: a Python package that is mostly pure Python, with a limited number of Cython extensions +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include Statsmodels, scikit-bio and QuTiP + +Main strategy: documentation. The functionality using Cython code will not support other array types (or only with conversion to/from ``numpy.ndarray``), which can be documented per function. + + +Situation 2: a Python package that contains a lot of Cython code +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include scikit-learn and scikit-image + +Main strategy: add support for other array types *per submodule*. This keeps it manageable to explain to the user which functionality does and doesn't have support. + +Longer term: specific support for particular array types (e.g. ``cupy.ndarray`` can be supported with Python-only code via ``cupy.ElementwiseKernel``). + + +Situation 3: a Python package that uses the NumPy or Python C API directly +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. note:: + Projects in this situation include SciPy and Astropy + +Strategy: similar to *situation 2*, but the number of submodules that can support all array types may be limited. + + +Device support +-------------- + +Supporting non-CPU array types in code using the C API or Cython seems problematic, +this almost inevitably will require custom device-specific code (e.g., CUDA, ROCm) or +something like JIT compilation with Numba. + + +Other longer-term approaches +---------------------------- + +Further Python API standardization +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +There may be cases where it makes sense to standardize additional sets of +functions, because they're important enough that array libraries tend to +reimplement them. An example of this may be *special functions*, as provided +by ``scipy.special``. Bessel and gamma functions for example are commonly +reimplemented by array libraries. This may avoid having to drop into a +particular implementation that does use a C API (e.g., one can then rely on +``arraylib.special.gamma`` rather than having to use ``scipy.special.gamma``). + +HPy +~~~ + +`HPy `_ is a new project that will provide a higher-level +C API and ABI than CPython offers. A Cython backend targeting HPy will be provided as well. + +- Better PyPy support +- Universal ABI - single binary for all supported Python versions +- Cython backend generating HPy rather than CPython code + +HPy isn't quite ready for mainstream usage today, but once it is it may +help make supporting multiple array libraries or adding non-CPU device +support to Cython more feasible. diff --git a/spec/2024.12/design_topics/accuracy.rst b/spec/2024.12/design_topics/accuracy.rst new file mode 100644 index 000000000..9d82dbb1f --- /dev/null +++ b/spec/2024.12/design_topics/accuracy.rst @@ -0,0 +1,93 @@ +.. _accuracy: + +Accuracy +======== + + Array API specification for minimum accuracy requirements. + +Arithmetic Operations +--------------------- + +The results of element-wise arithmetic operations + +- ``+`` +- ``-`` +- ``*`` +- ``/`` +- ``%`` + +including the corresponding element-wise array APIs defined in this standard + +- add +- subtract +- multiply +- divide + +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. By default, the rounding mode should be ``roundTiesToEven`` (i.e., round to nearest with ties rounded toward the nearest value with an even least significant bit). + +IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. Accordingly, conforming implementations may vary in their support for subnormal numbers. + +Mathematical Functions +---------------------- + +The results of the following functions + +- reciprocal +- sqrt + +for real-valued floating-point operands must return a correctly rounded value according to IEEE 754-2019 and a supported rounding mode. + +This specification does **not** precisely define the behavior of the following functions + +- acos +- acosh +- asin +- asinh +- atan +- atan2 +- atanh +- cos +- cosh +- exp +- expm1 +- hypot +- log +- log1p +- log2 +- log10 +- logaddexp +- pow +- sin +- sinh +- tan +- tanh + +except to require specific results for certain argument values that represent boundary cases of interest. + +.. note:: + To help readers identify functions lacking precisely defined accuracy behavior, this specification uses the phrase "implementation-dependent approximation" in function descriptions. + +For other argument values, these functions should compute approximations to the results of respective mathematical functions; however, this specification recognizes that array libraries may be constrained by underlying hardware and/or seek to optimize performance over absolute accuracy and, thus, allows some latitude in the choice of approximation algorithms. + +Although the specification leaves the choice of algorithms to the implementation, this specification recommends (but does not specify) that implementations use the approximation algorithms for IEEE 754-2019 arithmetic contained in `FDLIBM `_, the freely distributable mathematical library from Sun Microsystems, or some other comparable IEEE 754-2019 compliant mathematical library. + +.. note:: + With exception of a few mathematical functions, returning results which are indistinguishable from correctly rounded infinitely precise results is difficult, if not impossible, to achieve due to the algorithms involved, the limits of finite-precision, and error propagation. However, this specification recognizes that numerical accuracy alignment among array libraries is desirable in order to ensure portability and reproducibility. Accordingly, for each mathematical function, the specification test suite includes test values which span a function's domain and reports the average and maximum deviation from either a designated standard implementation (e.g., an arbitrary precision arithmetic implementation) or an average computed across a subset of known array library implementations. Such reporting aids users who need to know how accuracy varies among libraries and developers who need to check the validity of their implementations. + +Statistical Functions +--------------------- + +This specification does not specify accuracy requirements for statistical functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +.. note:: + In order for an array library to pass the specification test suite, an array library's statistical function implementations must satisfy certain bare-minimum accuracy requirements (e.g., accurate summation of a small set of positive integers). Unfortunately, imposing more rigorous accuracy requirements is not possible without severely curtailing possible implementation algorithms and unduly increasing implementation complexity. + +Linear Algebra +-------------- + +This specification does not specify accuracy requirements for linear algebra functions; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. + +Operations Involving Complex Numbers +------------------------------------ + +This specification does not specify accuracy requirements for arithmetic or functional operations involving complex-valued floating-point operands; however, this specification does expect that a conforming implementation of the array API standard will make a best-effort attempt to ensure that its implementations are theoretically sound and numerically robust. diff --git a/spec/2024.12/design_topics/complex_numbers.rst b/spec/2024.12/design_topics/complex_numbers.rst new file mode 100644 index 000000000..0eca79e91 --- /dev/null +++ b/spec/2024.12/design_topics/complex_numbers.rst @@ -0,0 +1,61 @@ +.. _complex-numbers: + +Complex Numbers +=============== + +The Complex Plane +----------------- + +Mathematically, equality comparison between complex numbers depends on the choice of topology. For example, the complex plane has a continuum of infinities; however, when the complex plane is projected onto the surface of a sphere (a stereographic projection commonly referred to as the *Riemann sphere*), infinities coalesce into a single *point at infinity*, thus modeling the extended complex plane. For the former, the value :math:`\infty + 3j` is distinct from (i.e., does not equal) :math:`\infty + 4j`, while, for the latter, :math:`\infty + 3j` does equal :math:`\infty + 4j`. + +Modeling complex numbers as a Riemann sphere conveys certain mathematical niceties (e.g., well-behaved division by zero and preservation of the identity :math:`\frac{1}{\frac{1}{z}} = z`); however, translating the model to IEEE 754 floating-point operations can lead to some unexpected results. For example, according to IEEE 754, :math:`+\infty` and :math:`-\infty` are distinct values; hence, for equality comparison, if :math:`x = +\infty` and :math:`y = -\infty`, then :math:`x \neq y`. In contrast, if we convert :math:`x` and :math:`y` to their complex number equivalents :math:`x = +\infty + 0j` and :math:`y = -\infty + 0j` and then interpret within the context of the extended complex plane, we arrive at the opposite result; namely, :math:`x = y`. + +In short, given the constraints of floating-point arithmetic and the subtleties of signed zeros, infinities, NaNs, and their interaction, crafting a specification which always yields intuitive results and satisfies all use cases involving complex numbers is not possible. Instead, this specification attempts to follow precedent (e.g., C99, Python, Julia, NumPy, and elsewhere), while also minimizing surprise. The result is an imperfect balance in which certain APIs may appear to embrace the one-infinity model found in C/C++ for algebraic operations involving complex numbers (e.g., considering :math:`\infty + \operatorname{NaN}\ j` to be infinite, irrespective of the imaginary component's value, including NaN), while other APIs may rely on the complex plane with its multiplicity of infinities (e.g., in transcendental functions). Accordingly, consumers of this specification should expect that certain results involving complex numbers for one operation may not be wholly consistent with results involving complex numbers for another operation. + + +.. _branch-cuts: + +Branch Cuts +----------- + +In the mathematical field of complex analysis, a **branch cut** is a curve in the complex plane across which an analytic multi-valued function is discontinuous. Branch cuts are often taken as lines or line segments, and the choice of any particular branch cut is a matter of convention. + +For example, consider the function :math:`z^2` which maps a complex number :math:`z` to a well-defined number :math:`z^2`. The function's inverse function :math:`\sqrt{z}` does not, however, map to a single value. For example, for :math:`z = 1`, :math:`\sqrt{1} = \pm 1`. While one can choose a unique principal value for this and similar functions (e.g., in this case, the principal square root is :math:`+1`), choices cannot be made continuous over the whole complex plane, as lines of discontinuity must occur. To handle discontinuities, one commonly adopts branch cuts, which are not, in general, unique. Instead, one chooses a branch cut as a matter of convention in order to give simple analytic properties. + +Branch cuts do not arise for single-valued trigonometric, hyperbolic, integer power, or exponential functions; however, branch cuts do arise for their multi-valued inverses. + +In contrast to real-valued floating-point numbers which have well-defined behavior as specified in IEEE 754, complex-valued floating-point numbers have no equivalent specification. Accordingly, this specification chooses to follow C99 conventions for special cases and branch cuts for those functions supporting complex numbers. For those functions which do not have C99 equivalents (e.g., linear algebra APIs), the specification relies on dominant conventions among existing array libraries. + +.. warning:: + All branch cuts documented in this specification are considered **provisional**. While conforming implementations of the array API standard should adopt the branch cuts described in this standard, consumers of array API standard implementations should **not** assume that branch cuts are consistent between implementations. + + Provided no issues arise due to the choice of branch cut, the provisional status is likely to be removed in a future revision of this standard. + + +.. _complex-number-ordering: + +Complex Number Ordering +----------------------- + +Given a set :math:`\{a_1, \ldots, a_n\}`, an order relation must satisfy the following properties: + +1. **Reflexive**: for any :math:`a` in the set, :math:`a \leq a`. +2. **Transitive**: for any :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`b \leq c`, then :math:`a \leq c`. +3. **Antisymmetric**: for any :math:`a` and :math:`b` in the set, if :math:`a \leq b` and :math:`b \leq a`, then :math:`a = b`. +4. **Total Order**: in addition to the *partial order* established by 1-3, for any :math:`a` and :math:`b` in the set, either :math:`a \leq b` or :math:`b \leq a` (or both). +5. **Compatible with Addition**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b`, then :math:`a + c \leq b + c`. +6. **Compatible with Multiplication**: for all :math:`a`, :math:`b`, and :math:`c` in the set, if :math:`a \leq b` and :math:`0 \leq c`, then :math:`ac \leq bc`. + +Defining an order relation for complex numbers which satisfies all six properties defined above is not possible. Accordingly, this specification does not require that a conforming implementation of the array API standard adopt any specific complex number order relation. + +In order to satisfy backward compatibility guarantees, conforming implementations of the array API standard may choose to define an ordering for complex numbers (e.g., lexicographic); however, consumers of the array API standard should **not** assume that complex number ordering is consistent between implementations or even supported. + +If a conforming implementation chooses to define an ordering for complex numbers, the ordering must be clearly documented. + + +Valued-based Promotion +---------------------- + +According to the type promotion rules described in this specification (see :ref:`type-promotion`), only the data types of the input arrays participating in an operation matter, not their values. The same principle applies to situations in which one or more results of operations on real-valued arrays are mathematically defined in the complex domain, but not in their real domain. + +By convention, the principal square root of :math:`-1` is :math:`j`, where :math:`j` is the imaginary unit. Despite this convention, for those operations supporting type promotion, conforming implementations must only consider input array data types when determining the data type of the output array. For example, if a real-valued input array is provided to :func:`~array_api.sqrt`, the output array must also be real-valued, even if the input array contains negative values. Accordingly, if a consumer of a conforming implementation of this specification desires for an operation's results to include the complex domain, the consumer should first cast the input array(s) to an appropriate complex floating-point data type before performing the operation. diff --git a/spec/2024.12/design_topics/copies_views_and_mutation.rst b/spec/2024.12/design_topics/copies_views_and_mutation.rst new file mode 100644 index 000000000..f302d8c8e --- /dev/null +++ b/spec/2024.12/design_topics/copies_views_and_mutation.rst @@ -0,0 +1,102 @@ +.. _copyview-mutability: + +Copy-view behavior and mutability +================================== + +.. admonition:: Mutating views + :class: important + + Array API consumers are *strongly* advised to avoid *any* mutating operations when an array object may either be a "view" (i.e., an array whose data refers to memory that belongs to another array) or own memory of which one or more other array objects may be views. This admonition may become more strict in the future (e.g., this specification may require that view mutation be prohibited and trigger an exception). Accordingly, only perform mutation operations (e.g., in-place assignment) when absolutely confident that array data belongs to one, and only one, array object. + +Strided array implementations (e.g. NumPy, PyTorch, CuPy, MXNet) typically +have the concept of a "view", meaning an array containing data in memory that +belongs to another array (i.e., a different "view" on the original data). +Views are useful for performance reasons—not copying data to a new location +saves memory and is faster than copying—but can also affect the semantics +of code. This happens when views are combined with *mutating* operations. +The following example is illustrative: + +.. code-block:: python + + x = ones(1) + y = x[:] # `y` *may* be a view on the data of `x` + y -= 1 # if `y` is a view, this modifies `x` + +Code similar to the above example will not be portable between array +libraries. For example, for NumPy, PyTorch, and CuPy, ``x`` will contain the value ``0``, +while, for TensorFlow, JAX, and Dask, ``x`` will contain the value ``1``. In +this case, the combination of views and mutability is fundamentally problematic +if the goal is to be able to write code with unambiguous semantics. + +Views are necessary for getting good performance out of the current strided +array libraries. It is not always clear, however, when a library will return a +view and when it will return a copy. This standard does not attempt to +specify this—libraries may do either. + +There are several types of operations that may perform in-place mutation of +array data. These include: + +1. In-place operators (e.g. ``*=``) +2. Item assignment (e.g. ``x[0] = 1``) +3. Slice assignment (e.g., ``x[:2, :] = 3``) +4. The `out=` keyword present in some strided array libraries (e.g. ``sin(x, out=y)``) + +Libraries such as TensorFlow and JAX tend to support in-place operators by providing +alternative syntax for item and slice assignment (e.g. an ``update_index`` +function or ``x.at[idx].set(y)``) and have no need for ``out=``. + +A potential solution could be to make views read-only or implement copy-on-write +semantics. Both are hard to implement and would present significant backward +compatibility issues for current strided array libraries. Read-only +views would also not be a full solution due to the fact that mutating the original +(base) array will also result in ambiguous semantics. Accordingly, this standard +does not attempt to pursue this solution. + +Both in-place operators and item/slice assignment can be mapped onto +equivalent functional expressions (e.g. ``x[idx] = val`` maps to +``x.at[idx].set(val)``), and, given that both in-place operators and item/slice +assignment are very widely used in both library and end user code, this +standard chooses to include them. + +The situation with ``out=`` is slightly different—it's less heavily used, and +easier to avoid. It's also not an optimal API because it mixes an +"efficiency of implementation" consideration ("you're allowed to do this +in-place") with the semantics of a function ("the output _must_ be placed into +this array"). There are libraries that do some form of tracing or abstract +interpretation over a vocabulary that does not support mutation (to make +analysis easier). In those cases implementing ``out=`` with correct handling of +views may even be impossible to do. + +There are alternatives. For example, the concept of donated arguments in JAX or +working buffers in LAPACK which allow the user to express "you _may_ overwrite +this data; do whatever is fastest". Given that those alternatives aren't widely +used in array libraries today, this standard chooses to (a) leave out ``out=``, +and (b) not specify another method of reusing arrays that are no longer needed +as buffers. + +This leaves the problem of the initial example—despite the best efforts of this +standard, it remains possible to write code that will not work the same for all +array libraries. This is something that the users are advised to best keep in +mind and to reason carefully about the potential ambiguity of implemented code. + + +.. _copy-keyword-argument: + +Copy keyword argument behavior +------------------------------ + +Several APIs in this standard support a ``copy`` keyword argument (e.g., +``asarray``, ``astype``, ``reshape``, and ``__dlpack__``). Typically, when a +user sets ``copy=True``, the user does so in order to ensure that they are free +to mutate the returned array without side-effects—namely, without mutating other +views on the original (base) array. Accordingly, when ``copy=True``, unless an +array library can guarantee that an array can be mutated without side-effects, +conforming libraries are recommended to always perform a physical copy of the +underlying array data. + +.. note:: + Typically, in order to provide such a guarantee, libraries must perform + whole-program analysis. + +Conversely, consumers of this standard should expect that, if they set +``copy=True``, they are free to use in-place operations on a returned array. diff --git a/spec/2024.12/design_topics/data_dependent_output_shapes.rst b/spec/2024.12/design_topics/data_dependent_output_shapes.rst new file mode 100644 index 000000000..43daa9765 --- /dev/null +++ b/spec/2024.12/design_topics/data_dependent_output_shapes.rst @@ -0,0 +1,15 @@ +.. _data-dependent-output-shapes: + +Data-dependent output shapes +============================ + +Array libraries which build computation graphs commonly employ static analysis that relies upon known shapes. For example, JAX requires known array sizes when compiling code, in order to perform static memory allocation. Functions and operations which are value-dependent present difficulties for such libraries, as array sizes cannot be inferred ahead of time without also knowing the contents of the respective arrays. + +While value-dependent functions and operations are not impossible to implement for array libraries which build computation graphs, this specification does not want to impose an undue burden on such libraries and permits omission of value-dependent operations. All other array libraries are expected, however, to implement the value-dependent operations included in this specification in order to be array specification compliant. + +Value-dependent operations are demarcated in this specification using an admonition similar to the following: + +.. admonition:: Data-dependent output shape + :class: important + + The shape of the output array for this function/operation depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function/operation difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. diff --git a/spec/2024.12/design_topics/data_interchange.rst b/spec/2024.12/design_topics/data_interchange.rst new file mode 100644 index 000000000..3b3040672 --- /dev/null +++ b/spec/2024.12/design_topics/data_interchange.rst @@ -0,0 +1,105 @@ +.. _data-interchange: + +Data interchange mechanisms +=========================== + +This section discusses the mechanism to convert one type of array into another. +As discussed in the :ref:`assumptions-dependencies ` section, +*functions* provided by an array library are not expected to operate on +*array types* implemented by another library. Instead, the array can be +converted to a "native" array type. + +The interchange mechanism must offer the following: + +1. Data access via a protocol that describes the memory layout of the array + in an implementation-independent manner. + + *Rationale: any number of libraries must be able to exchange data, and no + particular package must be needed to do so.* + +2. Support for all dtypes in this API standard (see :ref:`data-types`). + +3. Device support. It must be possible to determine on what device the array + that is to be converted lives. + + *Rationale: there are CPU-only, GPU-only, and multi-device array types; + it's best to support these with a single protocol (with separate + per-device protocols it's hard to figure out unambiguous rules for which + protocol gets used, and the situation will get more complex over time + as TPU's and other accelerators become more widely available).* + +4. Zero-copy semantics where possible, making a copy only if needed (e.g. + when data is not contiguous in memory). + + *Rationale: performance.* + +5. A Python-side and a C-side interface, the latter with a stable C ABI. + + *Rationale: all prominent existing array libraries are implemented in + C/C++, and are released independently from each other. Hence a stable C + ABI is required for packages to work well together.* + +DLPack: An in-memory tensor structure +------------------------------------- + +The best candidate for this protocol is +`DLPack `_, and hence that is what this +standard has chosen as the primary/recommended protocol. Note that the +``asarray`` function also supports the Python buffer protocol (CPU-only) to +support libraries that already implement buffer protocol support. + +.. note:: + The main alternatives to DLPack are device-specific methods: + + - The `buffer protocol `_ on CPU + - ``__cuda_array_interface__`` for CUDA, specified in the Numba documentation + `here `_ + (Python-side only at the moment) + + An issue with device-specific protocols are: if two libraries both + support multiple device types, in which order should the protocols be + tried? A growth in the number of protocols to support each time a new + device gets supported by array libraries (e.g. TPUs, AMD GPUs, emerging + hardware accelerators) also seems undesirable. + + In addition to the above argument, it is also clear from adoption + patterns that DLPack has the widest support. The buffer protocol, despite + being a lot older and standardized as part of Python itself via PEP 3118, + hardly has any support from array libraries. CPU interoperability is + mostly dealt with via the NumPy-specific ``__array__`` (which, when called, + means the object it is attached to must return a ``numpy.ndarray`` + containing the data the object holds). + + See the `RFC to adopt DLPack `_ + for discussion that preceded the adoption of DLPack. + +DLPack's documentation can be found at: https://dmlc.github.io/dlpack/latest/. + +The `Python specification of DLPack `__ +page gives a high-level specification for data exchange in Python using DLPack. + +.. note:: + DLPack is a standalone protocol/project and can therefore be used outside of + this standard. Python libraries that want to implement only DLPack support + are recommended to do so using the same syntax and semantics as outlined + below. They are not required to return an array object from ``from_dlpack`` + which conforms to this standard. + +Non-supported use cases +----------------------- + +Use of DLPack requires that the data can be represented by a strided, in-memory +layout on a single device. This covers usage by a large range of, but not all, +known and possible array libraries. Use cases that are not supported by DLPack +include: + +- Distributed arrays, i.e., the data residing on multiple nodes or devices, +- Sparse arrays, i.e., sparse representations where a data value (typically + zero) is implicit. + +There may be other reasons why it is not possible or desirable for an +implementation to materialize the array as strided data in memory. In such +cases, the implementation may raise a `BufferError` in the `__dlpack__` or +`__dlpack_device__` method. In case an implementation is never able to export +its array data via DLPack, it may omit `__dlpack__` and `__dlpack_device__` +completely, and hence `from_dlpack` may raise an `AttributeError`. diff --git a/spec/2024.12/design_topics/device_support.rst b/spec/2024.12/design_topics/device_support.rst new file mode 100644 index 000000000..593b0b9fa --- /dev/null +++ b/spec/2024.12/design_topics/device_support.rst @@ -0,0 +1,112 @@ +.. _device-support: + +Device support +============== + +For libraries that support execution on more than a single hardware device - e.g. CPU and GPU, or multiple GPUs - it is important to be able to control on which device newly created arrays get placed and where execution happens. Attempting to be fully implicit doesn't always scale well to situations with multiple GPUs. + +Existing libraries employ one or more of these three methods to exert such control over data placement: + +1. A global default device, which may be fixed or user-switchable. +2. A context manager to control device assignment within its scope. +3. Local control for data allocation target device via explicit keywords, and a method to transfer arrays to another device. + +Libraries differ in how execution is controlled, via a context manager or with the convention that execution takes place on the same device where all argument arrays are allocated. And they may or may not allow mixing arrays on different devices via implicit data transfers. + +This standard chooses to add support for method 3 (local control), with the convention that execution takes place on the same device where all argument arrays are allocated. The rationale for choosing method 3 is because it's the most explicit and granular, with its only downside being verbosity. A context manager may be added in the future - see :ref:`device-out-of-scope` for details. + +Intended usage +-------------- + +The intended usage for the device support in the current version of the +standard is *device handling in library code*. The assumed pattern is that +users create arrays (for which they can use all the relevant device syntax +that the library they use provides), and that they then pass those arrays +into library code which may have to do the following: + +- Create new arrays on the same device as an array that's passed in. +- Determine whether two input arrays are present on the same device or not. +- Move an array from one device to another. +- Create output arrays on the same device as the input arrays. +- Pass on a specified device to other library code. + +.. note:: + Given that there is not much that's currently common in terms of + device-related syntax between different array libraries, the syntax included + in the standard is kept as minimal as possible while enabling the + above-listed use cases. + +Syntax for device assignment +---------------------------- + +The array API provides the following syntax for device assignment and +cross-device data transfer: + +1. A ``.device`` property on the array object, which returns a ``Device`` object + representing the device the data in the array is stored on, and supports + comparing devices for equality with ``==`` and ``!=`` within the same library + (e.g., by implementing ``__eq__``); comparing device objects from different + libraries is out of scope). +2. A ``device=None`` keyword for array creation functions, which takes an + instance of a ``Device`` object. +3. A ``.to_device`` method on the array object to copy an array to a different device. + +.. note:: + The current API standard does **not** include a universal ``Device`` object + recognized by all compliant libraries. Accordingly, the standard does not + provide a means of instantiating a ``Device`` object to point to a specific + physical or logical device. + + The choice to not include a standardized ``Device`` object may be revisited + in a future revision of this standard. + + For array libraries which concern themselves with multi-device support, + including CPU and GPU, they are free to expose a library-specific device + object (e.g., for creating an array on a particular device). While a + library-specific device object can be used as input to ``to_device``, beware + that this will mean non-portability as code will be specific to that + library. + +Semantics +--------- + +Handling devices is complex, and some frameworks have elaborate policies for +handling device placement. Therefore this section only gives recommendations, +rather than hard requirements: + +- Respect explicit device assignment (i.e. if the input to the ``device=`` keyword is not ``None``, guarantee that the array is created on the given device, and raise an exception otherwise). +- Preserve device assignment as much as possible (e.g. output arrays from a function are expected to be on the same device as input arrays to the function). +- Raise an exception if an operation involves arrays on different devices (i.e. avoid implicit data transfer between devices). +- Use a default for ``device=None`` which is consistent between functions within the same library. +- If a library has multiple ways of controlling device placement, the most explicit method should have the highest priority. For example: + + 1. If ``device=`` keyword is specified, that always takes precedence + + 2. If ``device=None``, then use the setting from a context manager, if set. + + 3. If no context manager was used, then use the global default device/strategy + +.. _device-out-of-scope: + +Out of scope for device support +------------------------------- + +Individual libraries may offers APIs for one or more of the following topics, +however those are out of scope for this standard: + +- Identifying a specific physical or logical device across libraries +- Setting a default device globally +- Stream/queue control +- Distributed allocation +- Memory pinning +- A context manager for device control + +.. note:: + A context manager for controlling the default device is present in most existing array + libraries (NumPy being the exception). There are concerns with using a + context manager however. A context manager can be tricky to use at a high + level, since it may affect library code below function calls (non-local + effects). See, e.g., `this PyTorch issue `_ + for a discussion on a good context manager API. + + Adding a context manager may be considered in a future version of this API standard. diff --git a/spec/2024.12/design_topics/exceptions.rst b/spec/2024.12/design_topics/exceptions.rst new file mode 100644 index 000000000..570fe56e3 --- /dev/null +++ b/spec/2024.12/design_topics/exceptions.rst @@ -0,0 +1,28 @@ +.. _exceptions: + +Exceptions +========== + +This standard specifies expected syntax and semantics for a set of APIs. When +inputs to an API do not match what is expected, libraries may emit warnings, +raise exceptions, or misbehave in unexpected ways. In general, it is not +possible to foresee or specify all the ways in which unexpected or invalid +inputs are provided. Therefore, this standard does not attempt to specify +exception or warning types to the extent needed in order to do exception +handling in a portable manner. In general, it is expected that array library +implementers follow `the guidance given by the documentation of the Python +language `__, and either use +builtin exception or warning types that are appropriate for the +situation or use custom exceptions or warnings that derive from those builtin +ones. + +In specific cases, it may be useful to provide guidance to array library +authors regarding what an appropriate exception is. That guidance will be +phrased as *should* rather than *must* (typically in a *Raises* section), +because (a) there may be reasons for an implementer to deviate, and (b) more +often than not, existing array library implementation already differ in their +choices, and it may not be worth them breaking backward compatibility in order +to comply with a "must" in this standard. + +In other cases, this standard will only specify that an exception should or +must be raised, but not mention what type of exception that is. diff --git a/spec/2024.12/design_topics/index.rst b/spec/2024.12/design_topics/index.rst new file mode 100644 index 000000000..548eda90c --- /dev/null +++ b/spec/2024.12/design_topics/index.rst @@ -0,0 +1,18 @@ +Design topics & constraints +=========================== + +.. toctree:: + :caption: Design topics & constraints + :maxdepth: 1 + + copies_views_and_mutation + data_dependent_output_shapes + lazy_eager + data_interchange + device_support + static_typing + accuracy + exceptions + complex_numbers + C_API + parallelism diff --git a/spec/2024.12/design_topics/lazy_eager.rst b/spec/2024.12/design_topics/lazy_eager.rst new file mode 100644 index 000000000..63297ac73 --- /dev/null +++ b/spec/2024.12/design_topics/lazy_eager.rst @@ -0,0 +1,43 @@ +.. _lazy-eager: + +Lazy vs. eager execution +======================== + +While the execution model for implementations is out of scope of this standard, +there are a few aspects of lazy (or graph-based) execution as contrasted to +eager execution that may have an impact on the prescribed semantics of +individual APIs, and will therefore show up in the API specification. + +One important difference is data-dependent or value-dependent behavior, as +described in :ref:`data-dependent-output-shapes`. Because such behavior is hard +to implement, implementers may choose to omit such APIs from their library. + +Another difference is when the Python language itself prescribes that a +specific type *must* be returned. For those cases, it is not possible to return +a lazy/delayed kind of object to avoid computing a value. This is the case for +five dunder methods: `__bool__`, `__int__`, `__float__`, `__complex__` and +`__index__`. Each implementation has only two choices when one of these methods +is called: + +1. Compute a value of the required type (a Python scalar of type `bool`, `int`, + `float` or `complex`), or +2. Raise an exception. + +When an implementation is 100% lazy, for example when it serializes a +computation graph, computing the value is not possible and hence such an +implementation has no choice but to raise an exception. For a "mostly lazy" +implementation, it may make sense to trigger execution instead - but it is not +required to, both choices are valid. + +A common code construct where this happens is conditional logic, e.g.:: + + vals = compute_something() + if all(vals): + # The if-statement will make Python call the __bool__ method + # on the result of `all(vals)`. + do_something_else() + +Note that the API does not contain control flow constructs, as of now, that +would allow avoiding the implicit `__bool__` call in the example above. The +only control flow-like function is `where`, but there's no function like `cond` +to replace an `if`-statement. diff --git a/spec/2024.12/design_topics/parallelism.rst b/spec/2024.12/design_topics/parallelism.rst new file mode 100644 index 000000000..f013a9cf9 --- /dev/null +++ b/spec/2024.12/design_topics/parallelism.rst @@ -0,0 +1,24 @@ +Parallelism +=========== + +Parallelism is mostly, but not completely, an execution or runtime concern +rather than an API concern. Execution semantics are out of scope for this API +standard, and hence won't be discussed further here. The API related part +involves how libraries allow users to exercise control over the parallelism +they offer, such as: + +- Via environment variables. This is the method of choice for BLAS libraries and libraries using OpenMP. +- Via a keyword to individual functions or methods. Examples include the ``n_jobs`` keyword used in scikit-learn and the ``workers`` keyword used in SciPy. +- Build-time settings to enable a parallel or distributed backend. +- Via letting the user set chunk sizes. Dask uses this approach. + +When combining multiple libraries, one has to deal with auto-parallelization +semantics and nested parallelism. Two things that could help improve the +coordination of parallelization behavior in a stack of Python libraries are: + +1. A common API pattern for enabling parallelism +2. A common library providing a parallelization layer + +Option (1) may possibly fit in a future version of this array API standard. +`array-api issue 4 `_ contains +more detailed discussion on the topic of parallelism. diff --git a/spec/2024.12/design_topics/static_typing.rst b/spec/2024.12/design_topics/static_typing.rst new file mode 100644 index 000000000..26a1fb901 --- /dev/null +++ b/spec/2024.12/design_topics/static_typing.rst @@ -0,0 +1,50 @@ +Static typing +============= + +Good support for static typing both in array libraries and array-consuming +code is desirable. Therefore the exact type or set of types for each +parameter, keyword and return value is specified for functions and methods - +see :ref:`function-and-method-signatures`. That section specifies arrays +simply as ``array``; what that means is dealt with in this section. + +Introducing type annotations in libraries became more relevant only when +Python 2.7 support was dropped at the start of 2020. As a consequence, using +type annotations with array libraries is largely still a work in progress. +This version of the API standard does not deal with trying to type *array +properties* like shape, dimensionality or dtype, because that's not a solved +problem in individual array libraries yet. + +An ``array`` type annotation can mean either the type of one specific array +object, or some superclass or typing Protocol - as long as it is consistent +with the array object specified in :ref:`array-object`. To illustrate by +example: + +.. code-block:: python + + # `Array` is a particular class in the library + def sin(x: Array, / ...) -> Array: + ... + +and + +.. code-block:: python + + # There's some base class `_BaseArray`, and there may be multiple + # array subclasses inside the library + A = TypeVar('A', bound=_BaseArray) + def sin(x: A, / ...) -> A: + ... + +should both be fine. There may be other variations possible. Also note that +this standard does not require that input and output array types are the same +(they're expected to be defined in the same library though). Given that +array libraries don't have to be aware of other types of arrays defined in +other libraries (see :ref:`assumptions-dependencies`), this should be enough +for a single array library. + +That said, an array-consuming library aiming to support multiple array types +may need more - for example a protocol to enable structural subtyping. This +API standard currently takes the position that it does not provide any +reference implementation or package that can or should be relied on at +runtime, hence no such protocol is defined here. This may be dealt with in a +future version of this standard. diff --git a/spec/2024.12/extensions/fourier_transform_functions.rst b/spec/2024.12/extensions/fourier_transform_functions.rst new file mode 100644 index 000000000..170ae390b --- /dev/null +++ b/spec/2024.12/extensions/fourier_transform_functions.rst @@ -0,0 +1,45 @@ +Fourier transform Functions +=========================== + + Array API specification for Fourier transform functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``fft``. + +If implemented, this ``fft`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'fft'): + >>> # Use `xp.fft` + + +Objects in API +-------------- + +A conforming implementation of this ``fft`` extension must provide and support the following functions. + +.. currentmodule:: array_api.fft + +.. + NOTE: please keep the functions and their inverse together + +.. autosummary:: + :toctree: generated + :template: method.rst + + fft + ifft + fftn + ifftn + rfft + irfft + rfftn + irfftn + hfft + ihfft + fftfreq + rfftfreq + fftshift + ifftshift diff --git a/spec/2024.12/extensions/index.rst b/spec/2024.12/extensions/index.rst new file mode 100644 index 000000000..3b9409954 --- /dev/null +++ b/spec/2024.12/extensions/index.rst @@ -0,0 +1,34 @@ +.. _extensions: + +Extensions +========== + +Extensions are coherent sets of functionality that are commonly implemented +across array libraries. Each array library supporting this standard may, but is +not required to, implement an extension. If an extension is supported, it +must be accessible inside the main array API supporting namespace as a separate +namespace. + +Extension module implementors must aim to provide all functions and other +public objects in an extension. The rationale for this is that downstream usage +can then check whether or not the extension is present (using ``hasattr(xp, +'extension_name')`` should be enough), and can then assume that functions are +implemented. This in turn makes it also easy for array-consuming libraries to +document which array libraries they support - e.g., "all libraries implementing +the array API standard and its linear algebra extension". + +The mechanism through which the extension namespace is made available is up to +the implementer, e.g. via a regular submodule that is imported under the +``linalg`` name, or via a module-level ``__getattr__``. + +The functions in an extension must adhere to the same conventions as those in +the array API standard. See :ref:`api-specification`. + +------------------------------------------------------------------------------ + +.. toctree:: + :caption: Extension modules: + :maxdepth: 1 + + fourier_transform_functions + linear_algebra_functions diff --git a/spec/2024.12/extensions/linear_algebra_functions.rst b/spec/2024.12/extensions/linear_algebra_functions.rst new file mode 100644 index 000000000..938221c79 --- /dev/null +++ b/spec/2024.12/extensions/linear_algebra_functions.rst @@ -0,0 +1,116 @@ +.. _linear-algebra-extension: + +Linear Algebra Extension +======================== + + Array API specification for linear algebra functions. + +Extension name and usage +------------------------ + +The name of the namespace providing the extension must be: ``linalg``. + +If implemented, this ``linalg`` extension must be retrievable via:: + + >>> xp = x.__array_namespace__() + >>> if hasattr(xp, 'linalg'): + >>> # Use `xp.linalg` + + +Design Principles +----------------- + +A principal goal of this specification is to standardize commonly implemented interfaces among array libraries. While this specification endeavors to avoid straying too far from common practice, this specification does, with due restraint, seek to address design decisions arising more from historical accident than first principles. This is especially true for linear algebra APIs, which have arisen and evolved organically over time and have often been tied to particular underlying implementations (e.g., to BLAS and LAPACK). + +Accordingly, the standardization process affords the opportunity to reduce interface complexity among linear algebra APIs by inferring and subsequently codifying common design themes, thus allowing more consistent APIs. What follows is the set of design principles governing the APIs which follow: + +1. **Batching**: if an operation is explicitly defined in terms of matrices (i.e., two-dimensional arrays), then the associated interface should support "batching" (i.e., the ability to perform the operation over a "stack" of matrices). Example operations include: + + - ``inv``: computing the multiplicative inverse of a square matrix. + - ``cholesky``: performing Cholesky decomposition. + - ``matmul``: performing matrix multiplication. + +2. **Data types**: if an operation requires decimal operations and :ref:`type-promotion` semantics are undefined (e.g., as is the case for mixed-kind promotions), then the associated interface should be specified as being restricted to floating-point data types. While the specification uses the term "SHOULD" rather than "MUST", a conforming implementation of the array API standard should only ignore the restriction provided overly compelling reasons for doing so. Example operations which should be limited to floating-point data types include: + + - ``inv``: computing the multiplicative inverse. + - ``slogdet``: computing the natural logarithm of the absolute value of the determinant. + - ``norm``: computing the matrix or vector norm. + + Certain operations are solely comprised of multiplications and additions. Accordingly, associated interfaces need not be restricted to floating-point data types. However, careful consideration should be given to overflow, and use of floating-point data types may be more prudent in practice. Example operations include: + + - ``matmul``: performing matrix multiplication. + - ``trace``: computing the sum along the diagonal. + - ``cross``: computing the vector cross product. + + Lastly, certain operations may be performed independent of data type, and, thus, the associated interfaces should support all data types specified in this standard. Example operations include: + + - ``matrix_transpose``: computing the transpose. + - ``diagonal``: returning the diagonal. + +3. **Return values**: if an interface has more than one return value, the interface should return a namedtuple consisting of each value. + + In general, interfaces should avoid polymorphic return values (e.g., returning an array **or** a namedtuple, dependent on, e.g., an optional keyword argument). Dedicated interfaces for each return value type are preferred, as dedicated interfaces are easier to reason about at both the implementation level and user level. Example interfaces which could be combined into a single overloaded interface, but are not, include: + + - ``eigh``: computing both eigenvalues and eigenvectors. + - ``eigvalsh``: computing only eigenvalues. + +4. **Implementation agnosticism**: a standardized interface should eschew parameterization (including keyword arguments) biased toward particular implementations. + + Historically, at a time when all array computing happened on CPUs, BLAS and LAPACK underpinned most numerical computing libraries and environments. Naturally, language and library abstractions catered to the parameterization of those libraries, often exposing low-level implementation details verbatim in their higher-level interfaces, even if such choices would be considered poor or ill-advised by today's standards (e.g., NumPy's use of `UPLO` in `eigh`). However, the present day is considerably different. While still important, BLAS and LAPACK no longer hold a monopoly over linear algebra operations, especially given the proliferation of devices and hardware on which such operations must be performed. Accordingly, interfaces must be conservative in the parameterization they support in order to best ensure universality. Such conservatism applies even to performance optimization parameters afforded by certain hardware. + +5. **Orthogonality**: an interface should have clearly defined and delineated functionality which, ideally, has no overlap with the functionality of other interfaces in the specification. Providing multiple interfaces which can all perform the same operation creates unnecessary confusion regarding interface applicability (i.e., which interface is best at which time) and decreases readability of both library and user code. Where overlap is possible, the specification must be parsimonious in the number of interfaces, ensuring that each interface provides a unique and compelling abstraction. Examples of related interfaces which provide distinct levels of abstraction (and generality) include: + + - ``vecdot``: computing the dot product of two vectors. + - ``matmul``: performing matrix multiplication (including between two vectors and thus the dot product). + - ``tensordot``: computing tensor contractions (generalized sum-products). + - ``einsum``: expressing operations in terms of Einstein summation convention, including dot products and tensor contractions. + + The above can be contrasted with, e.g., NumPy, which provides the following interfaces for computing the dot product or related operations: + + - ``dot``: dot product, matrix multiplication, and tensor contraction. + - ``inner``: dot product. + - ``vdot``: dot product with flattening and complex conjugation. + - ``multi_dot``: chained dot product. + - ``tensordot``: tensor contraction. + - ``matmul``: matrix multiplication (dot product for two vectors). + - ``einsum``: Einstein summation convention. + + where ``dot`` is overloaded based on input array dimensionality and ``vdot`` and ``inner`` exhibit a high degree of overlap with other interfaces. By consolidating interfaces and more clearly delineating behavior, this specification aims to ensure that each interface has a unique purpose and defined use case. + +.. currentmodule:: array_api.linalg + +Objects in API +-------------- + +A conforming implementation of this ``linalg`` extension must provide and support the following functions. + +.. + NOTE: please keep the functions in alphabetical order + +.. autosummary:: + :toctree: generated + :template: method.rst + + cholesky + cross + det + diagonal + eigh + eigvalsh + inv + matmul + matrix_norm + matrix_power + matrix_rank + matrix_transpose + outer + pinv + qr + slogdet + solve + svd + svdvals + tensordot + trace + vecdot + vector_norm diff --git a/spec/2024.12/future_API_evolution.md b/spec/2024.12/future_API_evolution.md new file mode 100644 index 000000000..443f683d5 --- /dev/null +++ b/spec/2024.12/future_API_evolution.md @@ -0,0 +1,60 @@ +(future-API-evolution)= + +# Future API standard evolution + +## Scope extensions + +Proposals for scope extensions in a future version of the API standard will follow +the process documented at https://github.com/data-apis/governance/blob/master/process_document.md + +In summary, proposed new APIs go through several maturity stages, and will only be +accepted in a future version of this API standard once they have reached the "Final" +maturity stage, which means multiple array libraries have compliant implementations +and real-world experience from use of those implementations is available. + + +## Backwards compatibility + +Functions, objects, keywords and specified behavior are added to this API standard +only if those are already present in multiple existing array libraries, and if there is +data that those APIs are used. Therefore it is highly unlikely that future versions +of this standard will make backwards-incompatible changes. + +The aim is for future versions to be 100% backwards compatible with older versions. +Any exceptions must have strong rationales and be clearly documented in the updated +API specification. + + +(api-versioning)= + +## Versioning + +This API standard uses the following versioning scheme: + +- The version is date-based, in the form `yyyy.mm` (e.g., `2020.12`). +- The version shall not include a standard way to do `alpha`/`beta`/`rc` or + `.post`/`.dev` type versions. + _Rationale: that's for Python packages, not for a standard._ +- The version must be made available at runtime via an attribute + `__array_api_version__` by a compliant implementation, in `'yyyy.mm'` format + as a string, in the namespace that implements the API standard. + _Rationale: dunder version strings are the standard way of doing this._ + +No utilities for dealing with version comparisons need to be provided; given +the format simple string comparisons with Python operators (`=-`, `<`, `>=`, +etc.) will be enough. + +```{note} + +Rationale for the `yyyy.mm` versioning scheme choice: +the API will be provided as part of a library, which already has a versioning +scheme (typically PEP 440 compliant and in the form `major.minor.bugfix`), +and a way to access it via `module.__version__`. The API standard version is +completely independent from the package version. Given the standardization +process, it resembles a C/C++ versioning scheme (e.g. `C99`, `C++14`) more +than Python package versioning. +``` + +The frequency of releasing a new version of an API standard will likely be at +regular intervals and on the order of one year, however no assumption on +frequency of new versions appearing must be made. diff --git a/spec/2024.12/index.rst b/spec/2024.12/index.rst new file mode 100644 index 000000000..3e51cc68e --- /dev/null +++ b/spec/2024.12/index.rst @@ -0,0 +1,37 @@ +Python array API standard +========================= + +Contents +-------- + +.. toctree:: + :caption: Context + :maxdepth: 1 + + purpose_and_scope + use_cases + assumptions + +.. toctree:: + :caption: API + :maxdepth: 1 + + design_topics/index + future_API_evolution + API_specification/index + extensions/index + +.. toctree:: + :caption: Methodology and Usage + :maxdepth: 1 + + usage_data + verification_test_suite + benchmark_suite + +.. toctree:: + :caption: Other + :maxdepth: 1 + + changelog + license diff --git a/spec/2024.12/license.rst b/spec/2024.12/license.rst new file mode 100644 index 000000000..06ec75dfc --- /dev/null +++ b/spec/2024.12/license.rst @@ -0,0 +1,9 @@ +License +======= + +All content on this website and the corresponding +`GitHub repository `__ is licensed +under the following license: + + .. include:: ../../LICENSE + :parser: myst_parser.sphinx_ diff --git a/spec/2024.12/purpose_and_scope.md b/spec/2024.12/purpose_and_scope.md new file mode 100644 index 000000000..b2019b7dd --- /dev/null +++ b/spec/2024.12/purpose_and_scope.md @@ -0,0 +1,470 @@ +# Purpose and scope + +## Introduction + +Python users have a wealth of choice for libraries and frameworks for +numerical computing, data science, machine learning, and deep learning. New +frameworks pushing forward the state of the art in these fields are appearing +every year. One unintended consequence of all this activity and creativity +has been fragmentation in multidimensional array (a.k.a. tensor) libraries - +which are the fundamental data structure for these fields. Choices include +NumPy, Tensorflow, PyTorch, Dask, JAX, CuPy, MXNet, Xarray, and others. + +The APIs of each of these libraries are largely similar, but with enough +differences that it's quite difficult to write code that works with multiple +(or all) of these libraries. This array API standard aims to address that +issue, by specifying an API for the most common ways arrays are constructed +and used. + +Why not simply pick an existing API and bless that as the standard? In short, +because there are often good reasons for the current inconsistencies between +libraries. The most obvious candidate for that existing API is NumPy. However +NumPy was not designed with non-CPU devices, graph-based libraries, or JIT +compilers in mind. Other libraries often deviate from NumPy for good +(necessary) reasons. Choices made in this API standard are often the same +ones NumPy makes, or close to it, but are different where necessary to make +sure all existing array libraries can adopt this API. + + +### This API standard + +This document aims to standardize functionality that exists in most/all array +libraries and either is commonly used or is needed for +consistency/completeness. Usage is determined via analysis of downstream +libraries, see {ref}`usage-data`. An example of consistency is: there are +functional equivalents for all Python operators (including the rarely used +ones). + +Beyond usage and consistency, there's a set of use cases that inform the API +design to ensure it's fit for a wide range of users and situations - see +{ref}`use-cases`. + +A question that may arise when reading this document is: _"what about +functionality that's not present in this document?_ This: + +- means that there is no guarantee the functionality is present in libraries + adhering to the standard +- does _not_ mean that that functionality is unimportant +- may indicate that that functionality, if present in a particular array + library, is unlikely to be present in all other libraries + +### History + +The first library for numerical and scientific computing in Python was +Numeric, developed in the mid-1990s. In the early 2000s a second, similar +library, Numarray, was created. In 2005 NumPy was written, superceding both +Numeric and Numarray and resolving the fragmentation at that time. For +roughly a decade, NumPy was the only widely used array library. Over the past +~5 years, mainly due to the emergence of new hardware and the rise of deep +learning, many other libraries have appeared, leading to more severe +fragmentation. Concepts and APIs in newer libraries were often inspired by +(or copied from) those in older ones - and then changed or improved upon to +fit new needs and use cases. Individual library authors discussed ideas, +however there was never (before this array API standard) a serious attempt +to coordinate between all libraries to avoid fragmentation and arrive at a +common API standard. + +The idea for this array API standard grew gradually out of many conversations +between maintainers during 2019-2020. It quickly became clear that any +attempt to write a new "reference library" to fix the current fragmentation +was infeasible - unlike in 2005, there are now too many different use cases +and too many stakeholders, and the speed of innovation is too high. In May +2020 an initial group of maintainers was assembled in the [Consortium for +Python Data API Standards](https://data-apis.org/) to start drafting a +specification for an array API that could be adopted by each of the existing +array and tensor libraries. That resulted in this document, describing that +API. + + +(Scope)= + +## Scope (includes out-of-scope / non-goals) + +This section outlines what is in scope and out of scope for this API standard. + +### In scope + +The scope of the array API standard includes: + +- Functionality which needs to be included in an array library for it to adhere + to this standard. +- Names of functions, methods, classes and other objects. +- Function signatures, including type annotations. +- Semantics of functions and methods. I.e. expected outputs including precision + for and dtypes of numerical results. +- Semantics in the presence of `nan`'s, `inf`'s, empty arrays (i.e. arrays + including one or more dimensions of size `0`). +- Casting rules, broadcasting, indexing +- Data interchange. I.e. protocols to convert one type of array into another + type, potentially sharing memory. +- Device support. + +Furthermore, meta-topics included in this standard include: + +- Use cases for the API standard and assumptions made in it +- API standard adoption +- API standard versioning +- Future API standard evolution +- Array library and API standard versioning +- Verification of API standard conformance + +The concrete set of functionality that is in scope for this version of the +standard is shown in this diagram: + +![Scope of array API](../_static/images/scope_of_array_API.png) + + +**Goals** for the API standard include: + +- Make it possible for array-consuming libraries to start using multiple types + of arrays as inputs. +- Enable more sharing and reuse of code built on top of the core functionality + in the API standard. +- For authors of new array libraries, provide a concrete API that can be + adopted as is, rather than each author having to decide what to borrow from + where and where to deviate. +- Make the learning curve for users less steep when they switch from one array + library to another one. + + +### Out of scope + +1. Implementations of the standard are out of scope. + + _Rationale: the standard will consist of a document and an accompanying test + suite with which the conformance of an implementation can be verified. Actual + implementations will live in array libraries; no reference implementation is + planned._ + +2. Execution semantics are out of scope. This includes single-threaded vs. + parallel execution, task scheduling and synchronization, eager vs. delayed + evaluation, performance characteristics of a particular implementation of the + standard, and other such topics. + + _Rationale: execution is the domain of implementations. Attempting to specify + execution behavior in a standard is likely to require much more fine-grained + coordination between developers of implementations, and hence is likely to + become an obstacle to adoption._ + +3. Non-Python API standardization (e.g., Cython or NumPy C APIs) + + _Rationale: this is an important topic for some array-consuming libraries, + but there is no widely shared C/Cython API and hence it doesn't make sense at + this point in time to standardize anything. See + the [C API section](design_topics/C_API.rst) for more details._ + +4. Standardization of these dtypes is out of scope: bfloat16, extended + precision floating point, datetime, string, object and void dtypes. + + _Rationale: these dtypes aren't uniformly supported, and their inclusion at + this point in time could put a significant implementation burden on + libraries. It is expected that some of these dtypes - in particular + `bfloat16` - will be included in a future version of the standard._ + +5. The following topics are out of scope: I/O, polynomials, error handling, + testing routines, building and packaging related functionality, methods of + binding compiled code (e.g., `cffi`, `ctypes`), subclassing of an array + class, masked arrays, and missing data. + + _Rationale: these topics are not core functionality for an array library, + and/or are too tied to implementation details._ + +6. NumPy (generalized) universal functions, i.e. ufuncs and gufuncs. + + _Rationale: these are NumPy-specific concepts, and are mostly just a + particular way of building regular functions with a few extra + methods/properties._ + +7. Behaviour for unexpected/invalid input to functions and methods. + + _Rationale: there are a huge amount of ways in which users can provide + invalid or unspecified input to functionality in the standard. Exception + types or other resulting behaviour cannot be completely covered and would + be hard to make consistent between libraries._ + + +**Non-goals** for the API standard include: + +- Making array libraries identical so they can be merged. + + _Each library will keep having its own particular strength, whether it's + offering functionality beyond what's in the standard, performance advantages + for a given use case, specific hardware or software environment support, or + more._ + +- Implement a backend or runtime switching system to be able to switch from one + array library to another with a single setting or line of code. + + _This may be feasible, however it's assumed that when an array-consuming + library switches from one array type to another, some testing and possibly + code adjustment for performance or other reasons may be needed._ + +- Making it possible to mix multiple array libraries in function calls. + + _Most array libraries do not know about other libraries, and the functions + they implement may try to convert "foreign" input, or raise an exception. + This behaviour is hard to specify; ensuring only a single array type is + used is best left to the end user._ + + +### Implications of in/out of scope + +If something is out of scope and therefore will not be part of (the current +version of) the API standard, that means that there are no guarantees that that +functionality works the same way, or even exists at all, across the set of +array libraries that conform to the standard. It does _not_ imply that this +functionality is less important or should not be used. + + +## Stakeholders + +Arrays are fundamental to scientific computing, data science, and machine +learning and deep learning. Hence there are many stakeholders for an array API +standard. The _direct_ stakeholders of this standard are **authors/maintainers of +Python array libraries**. There are many more types of _indirect_ stakeholders +though, including: + +- maintainers of libraries and other programs which depend on array libraries + (called "array-consuming libraries" in the rest of this document) +- authors of non-Python array libraries +- developers of compilers and runtimes with array-specific functionality +- end users + +Libraries that are being actively considered - in terms of current behaviour and +API surface - during the creation of the first version of this standard +include: + +- [NumPy](https://numpy.org) +- [TensorFlow](https://www.tensorflow.org/) +- [PyTorch](https://pytorch.org/) +- [MXNet](https://numpy.mxnet.io/) +- [JAX](https://github.com/google/jax) +- [Dask](https://dask.org/) +- [CuPy](https://cupy.chainer.org/) + +Other Python array libraries that are currently under active development and +could adopt this API standard include: + +- [xarray](https://xarray.pydata.org/) +- [PyData/Sparse](https://sparse.pydata.org) +- [Weld](https://github.com/weld-project/weld) +- [Bohrium](https://bohrium.readthedocs.io/) +- [Arkouda](https://github.com/mhmerrill/arkouda) +- [Legate](https://research.nvidia.com/publication/2019-11_Legate-NumPy%3A-Accelerated) + +There are a huge amount of array-consuming libraries; some of the most +prominent ones that are being taken into account - in terms of current array +API usage or impact of design decisions on them - include (this list is likely +to grow it over time): + +- [Pandas](https://pandas.pydata.org/) +- [SciPy](https://github.com/scipy/scipy) +- [scikit-learn](https://scikit-learn.org/) +- [Matplotlib](https://matplotlib.org/) +- [scikit-image](https://scikit-image.org/) +- [NetworkX](https://networkx.github.io/) + +Array libraries in other languages, some of which may grow a Python API in the +future or have taken inspiration from NumPy or other array libraries, include: + +- [Xtensor](https://xtensor.readthedocs.io) (C++, cross-language) +- [XND](https://xnd.io/) (C, cross-language) +- [stdlib](https://stdlib.io/) (JavaScript) +- [rust-ndarray](https://github.com/rust-ndarray/ndarray) (Rust) +- [rray](https://github.com/r-lib/rray) (R) +- [ND4J](https://github.com/deeplearning4j/nd4j) (JVM) +- [NumSharp](https://github.com/SciSharp/NumSharp) (C#) + +Compilers, runtimes, and dispatching layers for which this API standard may be +relevant: + +- [Cython](https://cython.org/) +- [Numba](http://numba.pydata.org/) +- [Pythran](https://pythran.readthedocs.io/en/latest/) +- [Transonic](https://transonic.readthedocs.io) +- [ONNX](https://onnx.ai/) +- [Apache TVM](https://tvm.apache.org/) +- [MLIR](https://mlir.llvm.org/) +- [TACO](https://github.com/tensor-compiler/taco) +- [unumpy](https://github.com/Quansight-Labs/unumpy) +- [einops](https://github.com/arogozhnikov/einops) +- [Apache Arrow](https://arrow.apache.org/) + + + +## How to read this document + +For guidance on how to read and understand the type annotations included in this specification, consult the Python [documentation](https://docs.python.org/3/library/typing.html). + + +(how-to-adopt-this-api)= + +## How to adopt this API + +Most (all) existing array libraries will find something in this API standard +that is incompatible with a current implementation, and that they cannot +change due to backwards compatibility concerns. Therefore we expect that each +of those libraries will want to offer a standard-compliant API in a _new +namespace_. The question then becomes: how does a user access this namespace? + +The simplest method is: document the import to use to directly access the +namespace (e.g. `import package_name.array_api`). This has two issues though: + +1. Array-consuming libraries that want to support multiple array libraries + then have to explicitly import each library. +2. It is difficult to _version_ the array API standard implementation (see + {ref}`api-versioning`). + +To address both issues, a uniform way must be provided by a conforming +implementation to access the API namespace, namely a [method on the array +object](array.__array_namespace__): + +``` +xp = x.__array_namespace__() +``` + +The method must take one keyword, `api_version=None`, to make it possible to +request a specific API version: + +``` +xp = x.__array_namespace__(api_version='2020.10') +``` + +The `xp` namespace must contain all functionality specified in +{ref}`api-specification`. The namespace may contain other functionality; however, +including additional functionality is not recommended as doing so may hinder +portability and inter-operation of array libraries within user code. + +### Checking an array object for Compliance + +Array-consuming libraries are likely to want a mechanism for determining +whether a provided array is specification compliant. The recommended approach +to check for compliance is by checking whether an array object has an +`__array_namespace__` attribute, as this is the one distinguishing feature of +an array-compliant object. + +Checking for an `__array_namespace__` attribute can be implemented as a small +utility function similar to the following. + +```python +def is_array_api_obj(x): + return hasattr(x, '__array_namespace__') +``` + +```{note} +Providing a "reference library" on which people depend is out-of-scope for +the standard. Hence the standard cannot, e.g., provide an array ABC from +which libraries can inherit to enable an `isinstance` check. However, note +that the `numpy.array_api` implementation aims to provide a reference +implementation with only the behavior specified in this standard - it may +prove useful for verifying one is writing portable code. +``` + +### Discoverability of conforming implementations + +It may be useful to have a way to discover all packages in a Python +environment which provide a conforming array API implementation, and the +namespace that that implementation resides in. +To assist array-consuming libraries which need to create arrays originating +from multiple conforming array implementations, or developers who want to perform +for example cross-library testing, libraries may provide an +{pypa}`entry point ` in order to make an array API +namespace discoverable. + +:::{admonition} Optional feature +Given that entry points typically require build system & package installer +specific implementation, this standard chooses to recommend rather than +mandate providing an entry point. +::: + +The following code is an example for how one can discover installed +conforming libraries: + +```python +from importlib.metadata import entry_points + +try: + eps = entry_points()['array_api'] + ep = next(ep for ep in eps if ep.name == 'package_name') +except TypeError: + # The dict interface for entry_points() is deprecated in py3.10, + # supplanted by a new select interface. + ep = entry_points(group='array_api', name='package_name') + +xp = ep.load() +``` + +An entry point must have the following properties: + +- **group**: equal to `array_api`. +- **name**: equal to the package name. +- **object reference**: equal to the array API namespace import path. + + +* * * + +## Conformance + +A conforming implementation of the array API standard must provide and support +all the functions, arguments, data types, syntax, and semantics described in +this specification. + +A conforming implementation of the array API standard may provide additional +features (e.g., values, objects, properties, data types, functions, and function +arguments) beyond those described in this specification. + +Libraries which aim to provide a conforming implementation but haven't yet +completed such an implementation may, and are encouraged to, provide details on +the level of (non-)conformance. For details on how to do this, see +[Verification - measuring conformance](verification_test_suite.md). + + +* * * + +## Terms and Definitions + +For the purposes of this specification, the following terms and definitions apply. + + + +**array**: +a (usually fixed-size) multidimensional container of items of the same type and size. + +**axis**: +an array dimension. + +**branch cut**: +a curve in the complex plane across which a given complex function fails to be continuous. + +**broadcast**: +automatic (implicit) expansion of array dimensions to be of equal sizes without copying array data for the purpose of making arrays with different shapes have compatible shapes for element-wise operations. + +**compatible**: +two arrays whose dimensions are compatible (i.e., where the size of each dimension in one array is either equal to one or to the size of the corresponding dimension in a second array). + +**element-wise**: +an operation performed element-by-element, in which individual array elements are considered in isolation and independently of other elements within the same array. + +**matrix**: +a two-dimensional array. + +**rank**: +number of array dimensions (not to be confused with the number of linearly independent columns of a matrix). + +**shape**: +a tuple of `N` non-negative integers that specify the sizes of each dimension and where `N` corresponds to the number of dimensions. + +**singleton dimension**: +a dimension whose size is one. + +**vector**: +a one-dimensional array. + +* * * + +## Normative References + +The following referenced documents are indispensable for the application of this specification. + +- __IEEE 754-2019: IEEE Standard for Floating-Point Arithmetic.__ Institute of Electrical and Electronic Engineers, New York (2019). +- Scott Bradner. 1997. "Key words for use in RFCs to Indicate Requirement Levels". RFC 2119. doi:[10.17487/rfc2119](https://tools.ietf.org/html/rfc2119). diff --git a/spec/2024.12/usage_data.md b/spec/2024.12/usage_data.md new file mode 100644 index 000000000..c2dcd5d65 --- /dev/null +++ b/spec/2024.12/usage_data.md @@ -0,0 +1,86 @@ +(usage-data)= + +# Usage Data + +> Summary of existing array API design and usage. + +## Introduction + +With rare exception, technical standardization ("standardization") occurs neither in a vacuum nor from first principles. Instead, standardization finds its origins in two or more, sometimes competing, implementations differing in design and behavior. These differences introduce friction as those (e.g., downstream end-users and library authors) who operate at higher levels of abstraction must either focus on an implementation subset (e.g., only NumPy-like array libraries) or accommodate variation through increased complexity (e.g., if NumPy array, call method `.foo()`; else if Dask array, call method `.bar()`). + +Standardization aspires to reduce this friction and is a process which codifies that which is common, while still encouraging experimentation and innovation. Through the process of standardization, implementations can align around a subset of established practices and channel development resources toward that which is new and novel. In short, standardization aims to thwart reinventing the proverbial wheel. + +A foundational step in standardization is articulating a subset of established practices and defining those practices in unambiguous terms. To this end, the standardization process must approach the problem from two directions: **design** and **usage**. The former direction seeks to understand + +- current implementation design (APIs, names, signatures, classes, and objects) +- current implementation semantics (calling conventions and behavior) + +while the latter direction seeks to quantify API + +- consumers (e.g., which downstream libraries utilize an API?) +- usage frequency (e.g., how often is an API consumed?) +- consumption patterns (e.g., which optional arguments are provided and in what context?) + +By analyzing both design and usage, the standardization process grounds specification decisions in empirical data and analysis. + +## Design + +To understand API design, standardization follows the following process. + +- Identify a representative sample of commonly used Python array libraries (e.g., NumPy, Dask Array, CuPy, MXNet, JAX, TensorFlow, and PyTorch). +- Acquire public APIs (e.g., by analyzing module exports and scraping public documentation). +- Unify and standardize public API data representation for subsequent analysis. +- Extract commonalities and differences by analyzing the intersection and complement of available APIs. +- Derive a common API subset suitable for standardization (based on prevalence and ease of implementation), where such a subset may include attribute names, method names, and positional and keyword arguments. +- Leverage usage data to validate API need and to inform naming conventions, supported data types, and/or optional arguments. +- Summarize findings and provide tooling for additional analysis and exploration. + +See the [`array-api-comparison`](https://github.com/data-apis/array-api-comparison) +repository for design data and summary analysis. + +## Usage + +To understand usage patterns, standardization follows the following process. + +- Identify a representative sample of commonly used Python libraries ("downstream libraries") which consume the subset of array libraries identified during design analysis (e.g., pandas, Matplotlib, SciPy, Xarray, scikit-learn, and scikit-image). +- Instrument downstream libraries in order to record Python array API calls. +- Collect traces while running downstream library test suites. +- Transform trace data into structured data (e.g., as JSON) for subsequent analysis. +- Generate empirical APIs based on provided arguments and associated types, noting which downstream library called which empirical API and at what frequency. +- Derive a single inferred API which unifies the individual empirical API calling semantics. +- Organize API results in human-readable form as type definition files. +- Compare the inferred API to the documented API. + +The following is an inferred API for `numpy.arange`. The docstring includes the number of lines of code that invoked this function for each downstream library when running downstream library test suites. + +```python +def arange( + _0: object, + /, + *_args: object, + dtype: Union[type, str, numpy.dtype, None] = ..., + step: Union[int, float] = ..., + stop: int = ..., +): + """ + usage.dask: 347 + usage.matplotlib: 359 + usage.pandas: 894 + usage.sample-usage: 4 + usage.scipy: 1173 + usage.skimage: 174 + usage.sklearn: 373 + usage.xarray: 666 + """ + ... +``` + +See the [`python-record-api`](https://github.com/data-apis/python-record-api) repository for source code, usage data, and analysis. To perform a similar analysis on additional downstream libraries, including those not publicly released, see the published PyPI [package](https://pypi.org/project/record_api/). + +## Use in Decision-Making + +Design and usage data support specification decision-making in the following ways. + +- Validate user stories to ensure that proposals satisfy existing needs. +- Define scope to ensure that proposals address general array library design requirements (i.e., proposals must have broad applicability and be possible to implement with a reasonable amount of effort). +- Inform technical design discussions to ensure that proposals are grounded in empirical data. diff --git a/spec/2024.12/use_cases.md b/spec/2024.12/use_cases.md new file mode 100644 index 000000000..e24aa50db --- /dev/null +++ b/spec/2024.12/use_cases.md @@ -0,0 +1,235 @@ +(use-cases)= + +# Use cases + +Use cases inform the requirements for, and design choices made in, this array +API standard. This section first discusses what types of use cases are +considered, and then works out a few concrete use cases in more detail. + +## Types of use cases + +- Packages that depend on a specific array library currently, and would like + to support multiple of them (e.g. for GPU or distributed array support, for + improved performance, or for reaching a wider user base). +- Writing new libraries/tools that wrap multiple array libraries. +- Projects that implement new types of arrays with, e.g., hardware-specific + optimizations or auto-parallelization behavior, and need an API to put on + top that is familiar to end users. +- End users that want to switch from one library to another without learning + about all the small differences between those libraries. + + +## Concrete use cases + +- {ref}`use-case-scipy` +- {ref}`use-case-einops` +- {ref}`use-case-xtensor` +- {ref}`use-case-numba` + + +(use-case-scipy)= + +### Use case 1: add hardware accelerator and distributed support to SciPy + +When surveying a representative set of advanced users and research software +engineers in 2019 (for [this NSF proposal](https://figshare.com/articles/Mid-Scale_Research_Infrastructure_-_The_Scientific_Python_Ecosystem/8009441)), +the single most common pain point brought up about SciPy was performance. + +SciPy heavily relies on NumPy (its only non-optional runtime dependency). +NumPy provides an array implementation that's in-memory, CPU-only and +single-threaded. Common performance-related wishes users have are: + +- parallel algorithms (can be multi-threaded or multiprocessing based) +- support for distributed arrays (with Dask in particular) +- support for GPUs and other hardware accelerators (shortened to just "GPU" + in the rest of this use case) + +Some parallelism can be supported in SciPy, it has a `workers` keyword +(similar to scikit-learn's `n_jobs` keyword) that allows specifying to use +parallelism in some algorithms. However SciPy itself will not directly start +depending on a GPU or distributed array implementation, or contain (e.g.) +CUDA code - that's not maintainable given the resources for development. +_However_, there is a way to provide distributed or GPU support. Part of the +solution is provided by NumPy's "array protocols" (see [gh-1](https://github.com/data-apis/array-api/issues/1)), that allow +dispatching to other array implementations. The main problem then becomes how +to know whether this will work with a particular distributed or GPU array +implementation - given that there are zero other array implementations that +are even close to providing full NumPy compatibility - without adding that +array implementation as a dependency. + +It's clear that SciPy functionality that relies on compiled extensions (C, +C++, Cython, Fortran) directly can't easily be run on another array library +than NumPy (see [C API](design_topics/C_API.rst) for more details about this topic). Pure Python +code can work though. There's two main possibilities: + +1. Testing with another package, manually or in CI, and simply provide a list + of functionality that is found to work. Then make ad-hoc fixes to expand + the set that works. +2. Start relying on a well-defined subset of the NumPy API (or a new + NumPy-like API), for which compatibility is guaranteed. + +Option (2) seems strongly preferable, and that "well-defined subset" is _what +an API standard should provide_. Testing will still be needed, to ensure there +are no critical corner cases or bugs between array implementations, however +that's then a very tractable task. + +As a concrete example, consider the spectral analysis functions in `scipy.signal`. +All of those functions (e.g., `periodogram`, `spectrogram`, `csd`, `welch`, `stft`, +`istft`) are pure Python - with the exception of `lombscargle` which is ~40 +lines of Cython - and uses NumPy function calls, array attributes and +indexing. The beginning of each function could be changed to retrieve the +module that implements the array API standard for the given input array type, +and then functions from that module could be used instead of NumPy functions. + +If the user has another array type, say a CuPy or PyTorch array `x` on their +GPU, doing: +``` +from scipy import signal + +signal.welch(x) +``` +will result in: +``` +# For CuPy +ValueError: object __array__ method not producing an array + +# For PyTorch +TypeError: can't convert cuda:0 device type tensor to numpy. +``` +and therefore the user will have to explicitly convert to and from a +`numpy.ndarray` (which is quite inefficient): +``` +# For CuPy +x_np = cupy.asnumpy(x) +freq, Pxx = (cupy.asarray(res) for res in signal.welch(x_np)) + +# For PyTorch +x_np = x.cpu().numpy() +# Note: ends up with tensors on CPU, may still have to move them back +freq, Pxx = (torch.tensor(res) for res in signal.welch(x_np)) +``` +This code will look a little different for each array library. The end goal +here is to be able to write this instead as: +``` +freq, Pxx = signal.welch(x) +``` +and have `freq`, `Pxx` be arrays of the same type and on the same device as `x`. + +```{note} + +This type of use case applies to many other libraries, from scikit-learn +and scikit-image to domain-specific libraries like AstroPy and +scikit-bio, to code written for a single purpose or user. +``` + +(use-case-einops)= + +### Use case 2: simplify einops by removing the backend system + +[einops](https://github.com/arogozhnikov/einops) is a library that provides flexible tensor operations and supports many array libraries (NumPy, TensorFlow, PyTorch, CuPy, MXNet, JAX). +Most of the code in `einops` is: + +- [einops.py](https://github.com/arogozhnikov/einops/blob/master/einops/einops.py) + contains the functions it offers as public API (`rearrange`, `reduce`, `repeat`). +- [_backends.py](https://github.com/arogozhnikov/einops/blob/master/einops/_backends.py) + contains the glue code needed to support that many array libraries. + +The amount of code in each of those two files is almost the same (~550 LoC each). +The typical pattern in `einops.py` is: +``` +def some_func(x): + ... + backend = get_backend(x) + shape = backend.shape(x) + result = backend.reduce(x) + ... +``` +With a standard array API, the `_backends.py` glue layer could almost completely disappear, +because the purpose it serves (providing a unified interface to array operations from each +of the supported backends) is already addressed by the array API standard. +Hence the complete `einops` code base could be close to 50% smaller, and easier to maintain or add to. + +```{note} + +Other libraries that have a similar backend system to support many array libraries +include [TensorLy](https://github.com/tensorly/tensorly), the (now discontinued) +multi-backend version of [Keras](https://github.com/keras-team/keras), +[Unumpy](https://github.com/Quansight-Labs/unumpy) and +[EagerPy](https://github.com/jonasrauber/eagerpy). Many end users and +organizations will also have such glue code - it tends to be needed whenever +one tries to support multiple array types in a single API. +``` + + +(use-case-xtensor)= + +### Use case 3: adding a Python API to xtensor + +[xtensor](https://github.com/xtensor-stack/xtensor) is a C++ array library +that is NumPy-inspired and provides lazy arrays. It has Python (and Julia and R) +bindings, however it does not have a Python array API. + +Xtensor aims to follow NumPy closely, however it only implements a subset of functionality +and documents some API differences in +[Notable differences with NumPy](https://xtensor.readthedocs.io/en/latest/numpy-differences.html). + +Note that other libraries document similar differences, see for example +[this page for JAX](https://jax.readthedocs.io/en/latest/jax.numpy.html) and +[this page for TensorFlow](https://www.tensorflow.org/guide/tf_numpy). + +Each time an array library author designs a new API, they have to choose (a) +what subset of NumPy makes sense to implement, and (b) where to deviate +because NumPy's API for a particular function is suboptimal or the semantics +don't fit their execution model. + +This array API standard aims to provide an API that can be readily adopted, +without having to make the above-mentioned choices. + +```{note} + +XND is another array library, written in C, that still needs a Python API. +Array implementations in other languages are often in a similar situation, +and could translate this array API standard 1:1 to their language. +``` + + +(use-case-numba)= + +### Use case 4: make JIT compilation of array computations easier and more robust + +[Numba](https://github.com/numba/numba) is a Just-In-Time (JIT) compiler for +numerical functions in Python; it is NumPy-aware. [PyPy](https://pypy.org) +is an implementation of Python with a JIT at its core; its NumPy support relies +on running NumPy itself through a compatibility layer (`cpyext`), while a +previous attempt to implement NumPy support directly was unsuccessful. + +Other array libraries may have an internal JIT (e.g., TensorFlow, PyTorch, +JAX, MXNet) or work with an external JIT like +[XLA](https://www.tensorflow.org/xla) or [VTA](https://tvm.apache.org/docs/vta/index.html). + +Numba currently has to jump through some hoops to accommodate NumPy's casting rules +and may not attain full compatibility with NumPy in some cases - see, e.g., +[this](https://github.com/numba/numba/issues/4749) or +[this](https://github.com/numba/numba/issues/5907) example issue regarding (array) scalar +return values. + +An [explicit suggestion from a Numba developer](https://twitter.com/esc___/status/1295389487485333505) +for this array API standard was: + +> for JIT compilers (e.g. Numba) it will be important, that the type of the + returned value(s) depends only on the *types* of the input but not on the + *values*. + +A concrete goal for this use case is to have better matching between +JIT-compiled and non-JIT execution. Here is an example from the Numba code +base, the need for which should be avoided in the future: + +``` +def check(x, y): + got = cfunc(x, y) + np.testing.assert_array_almost_equal(got, pyfunc(x, y)) + # Check the power operation conserved the input's dtype + # (this is different from Numpy, whose behaviour depends on + # the *values* of the arguments -- see PyArray_CanCastArrayTo). + self.assertEqual(got.dtype, x.dtype) +``` diff --git a/spec/2024.12/verification_test_suite.md b/spec/2024.12/verification_test_suite.md new file mode 100644 index 000000000..cbe770e48 --- /dev/null +++ b/spec/2024.12/verification_test_suite.md @@ -0,0 +1,62 @@ +# Verification - test suite + +## Measuring conformance + +In addition to the specification documents, a test suite is being developed to +aid library developers check conformance to the spec. **NOTE: The test suite +is still a work in progress.** It can be found at +. + +It is important to note that while the aim of the array API test suite is to +cover as much of the spec as possible, there are necessarily some aspects of +the spec that are not covered by the test suite, typically because they are +impossible to effectively test. Furthermore, if the test suite appears to +diverge in any way from what the spec documents say, this should be considered +a bug in the test suite. The specification is the ground source of truth. + +## Running the tests + +To run the tests, first clone the [test suite +repo](https://github.com/data-apis/array-api-tests), and install the testing +dependencies, + + pip install pytest hypothesis + +or + + conda install pytest hypothesis + +as well as the array libraries that you want to test. To run the tests, you +need to specify the array library that is to be tested. There are two ways to +do this. One way is to set the `ARRAY_API_TESTS_MODULE` environment variable. +For example + + ARRAY_API_TESTS_MODULE=numpy pytest + +Alternatively, edit the `array_api_tests/_array_module.py` file and change the +line + +```py +array_module = None +``` + +to + +```py +import numpy as array_module +``` + +(replacing `numpy` with the array module namespace to be tested). + +In either case, the tests should be run with the `pytest` command. + +Aside from the two testing dependencies (`pytest` and `hypothesis`), the test +suite has no dependencies. In particular, it does not depend on any specific +array libraries such as NumPy. All tests are run using only the array library +that is being tested, comparing results against the behavior as defined in the +spec. The test suite is designed to be standalone so that it can easily be vendored. + +See the +[README](https://github.com/data-apis/array-api-tests/blob/master/README.md) +in the test suite repo for more information about how to run and interpret the +test suite results. diff --git a/spec/_ghpages/versions.json b/spec/_ghpages/versions.json index 04777bd78..65a52628a 100644 --- a/spec/_ghpages/versions.json +++ b/spec/_ghpages/versions.json @@ -2,6 +2,7 @@ "2021.12": "2021.12", "2022.12": "2022.12", "2023.12": "2023.12", + "2024.12": "2024.12", "latest": "latest", "draft": "draft" } diff --git a/src/_array_api_conf.py b/src/_array_api_conf.py index 08929cc43..e8d4629f2 100644 --- a/src/_array_api_conf.py +++ b/src/_array_api_conf.py @@ -17,7 +17,7 @@ # -- Project information ----------------------------------------------------- project = "Python array API standard" -copyright = "2020-2024, Consortium for Python Data API Standards" +copyright = "2020-2025, Consortium for Python Data API Standards" author = "Consortium for Python Data API Standards" # -- General configuration --------------------------------------------------- diff --git a/src/array_api_stubs/_2024_12/__init__.py b/src/array_api_stubs/_2024_12/__init__.py new file mode 100644 index 000000000..537ea8f85 --- /dev/null +++ b/src/array_api_stubs/_2024_12/__init__.py @@ -0,0 +1,25 @@ +"""Function stubs and API documentation for the array API standard.""" + +from .array_object import * +from .constants import * +from .creation_functions import * +from .data_type_functions import * +from . import 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 .set_functions import * +from .sorting_functions import * +from .statistical_functions import * +from .utility_functions import * +from . import linalg +from . import fft +from .info import __array_namespace_info__ + + +__array_api_version__: str = "YYYY.MM" +""" +String representing the version of the array API specification which the conforming implementation adheres to. +""" diff --git a/src/array_api_stubs/_2024_12/_types.py b/src/array_api_stubs/_2024_12/_types.py new file mode 100644 index 000000000..f2fa356f2 --- /dev/null +++ b/src/array_api_stubs/_2024_12/_types.py @@ -0,0 +1,149 @@ +""" +Types for type annotations used in the array API standard. + +The type variables should be replaced with the actual types for a given +library, e.g., for NumPy TypeVar('array') would be replaced with ndarray. +""" +from __future__ import annotations + +__all__ = [ + "Any", + "List", + "Literal", + "NestedSequence", + "Optional", + "PyCapsule", + "SupportsBufferProtocol", + "SupportsDLPack", + "Tuple", + "Union", + "Sequence", + "array", + "device", + "dtype", + "ellipsis", + "finfo_object", + "iinfo_object", + "Enum", + "DefaultDataTypes", + "DataTypes", + "Capabilities", + "Info", +] + +from dataclasses import dataclass +from typing import ( + Any, + List, + Literal, + Optional, + Sequence, + Tuple, + TypedDict, + TypeVar, + Union, + Protocol, +) +from enum import Enum + +array = TypeVar("array") +device = TypeVar("device") +dtype = TypeVar("dtype") +SupportsDLPack = TypeVar("SupportsDLPack") +SupportsBufferProtocol = TypeVar("SupportsBufferProtocol") +PyCapsule = TypeVar("PyCapsule") +# ellipsis cannot actually be imported from anywhere, so include a dummy here +# to keep pyflakes happy. https://github.com/python/typeshed/issues/3556 +ellipsis = TypeVar("ellipsis") + + +@dataclass +class finfo_object: + """Dataclass returned by `finfo`.""" + + bits: int + eps: float + max: float + min: float + smallest_normal: float + dtype: dtype + + +@dataclass +class iinfo_object: + """Dataclass returned by `iinfo`.""" + + bits: int + max: int + min: int + dtype: dtype + + +_T_co = TypeVar("_T_co", covariant=True) + + +class NestedSequence(Protocol[_T_co]): + def __getitem__(self, key: int, /) -> Union[_T_co, NestedSequence[_T_co]]: + ... + + def __len__(self, /) -> int: + ... + + +class Info(Protocol): + """Namespace returned by `__array_namespace_info__`.""" + + def capabilities(self) -> Capabilities: + ... + + def default_device(self) -> device: + ... + + def default_dtypes(self, *, device: Optional[device]) -> DefaultDataTypes: + ... + + def devices(self) -> List[device]: + ... + + def dtypes( + self, *, device: Optional[device], kind: Optional[Union[str, Tuple[str, ...]]] + ) -> DataTypes: + ... + + +DefaultDataTypes = TypedDict( + "DefaultDataTypes", + { + "real floating": dtype, + "complex floating": dtype, + "integral": dtype, + "indexing": dtype, + }, +) +DataTypes = TypedDict( + "DataTypes", + { + "bool": dtype, + "float32": dtype, + "float64": dtype, + "complex64": dtype, + "complex128": dtype, + "int8": dtype, + "int16": dtype, + "int32": dtype, + "int64": dtype, + "uint8": dtype, + "uint16": dtype, + "uint32": dtype, + "uint64": dtype, + }, + total=False, +) +Capabilities = TypedDict( + "Capabilities", + { + "boolean indexing": bool, + "data-dependent shapes": bool, + "max rank": Optional[int], + }, +) diff --git a/src/array_api_stubs/_2024_12/array_object.py b/src/array_api_stubs/_2024_12/array_object.py new file mode 100644 index 000000000..08d5c0b6e --- /dev/null +++ b/src/array_api_stubs/_2024_12/array_object.py @@ -0,0 +1,1250 @@ +from __future__ import annotations + +__all__ = ["array"] + +from ._types import ( + array, + dtype as Dtype, + device as Device, + Optional, + Tuple, + Union, + Any, + PyCapsule, + Enum, + ellipsis, +) + + +class _array: + def __init__(self: array) -> None: + """Initialize the attributes for the array object class.""" + + @property + def dtype(self: array) -> Dtype: + """ + Data type of the array elements. + + Returns + ------- + out: dtype + array data type. + """ + + @property + def device(self: array) -> Device: + """ + Hardware device the array data resides on. + + Returns + ------- + out: device + a ``device`` object (see :ref:`device-support`). + """ + + @property + def mT(self: array) -> array: + """ + Transpose of a matrix (or a stack of matrices). + + If an array instance has fewer than two dimensions, an error should be raised. + + Returns + ------- + out: array + array whose last two dimensions (axes) are permuted in reverse order relative to original array (i.e., for an array instance having shape ``(..., M, N)``, the returned array must have shape ``(..., N, M)``). The returned array must have the same data type as the original array. + """ + + @property + def ndim(self: array) -> int: + """ + Number of array dimensions (axes). + + Returns + ------- + out: int + number of array dimensions (axes). + """ + + @property + def shape(self: array) -> Tuple[Optional[int], ...]: + """ + Array dimensions. + + Returns + ------- + out: Tuple[Optional[int], ...] + array dimensions. An array dimension must be ``None`` if and only if a dimension is unknown. + + + .. note:: + For array libraries having graph-based computational models, array dimensions may be unknown due to data-dependent operations (e.g., boolean indexing; ``A[:, B > 0]``) and thus cannot be statically resolved without knowing array contents. + + .. note:: + The returned value should be a tuple; however, where warranted, an array library may choose to return a custom shape object. If an array library returns a custom shape object, the object must be immutable, must support indexing for dimension retrieval, and must behave similarly to a tuple. + """ + + @property + def size(self: array) -> Optional[int]: + """ + Number of elements in an array. + + .. note:: + This must equal the product of the array's dimensions. + + Returns + ------- + out: Optional[int] + number of elements in an array. The returned value must be ``None`` if and only if one or more array dimensions are unknown. + + + .. note:: + For array libraries having graph-based computational models, an array may have unknown dimensions due to data-dependent operations. + """ + + @property + def T(self: array) -> array: + """ + Transpose of the array. + + The array instance must be two-dimensional. If the array instance is not two-dimensional, an error should be raised. + + Returns + ------- + out: array + two-dimensional array whose first and last dimensions (axes) are permuted in reverse order relative to original array. The returned array must have the same data type as the original array. + + + .. note:: + Limiting the transpose to two-dimensional arrays (matrices) deviates from the NumPy et al practice of reversing all axes for arrays having more than two-dimensions. This is intentional, as reversing all axes was found to be problematic (e.g., conflicting with the mathematical definition of a transpose which is limited to matrices; not operating on batches of matrices; et cetera). In order to reverse all axes, one is recommended to use the functional ``permute_dims`` interface found in this specification. + """ + + def __abs__(self: array, /) -> array: + """ + Calculates the absolute value for each element of an array instance. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise absolute value. If ``self`` has a real-valued data type, the returned array must have the same data type as ``self``. If ``self`` has a complex floating-point data type, the returned arrayed must have a real-valued floating-point data type whose precision matches the precision of ``self`` (e.g., if ``self`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.abs`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __add__(self: array, other: Union[int, float, complex, array], /) -> array: + """ + Calculates the sum for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance (augend array). Should have a numeric data type. + other: Union[int, float, array] + addend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __and__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i & other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_and`. + """ + + def __array_namespace__( + self: array, /, *, api_version: Optional[str] = None + ) -> Any: + """ + Returns an object that has all the array API functions on it. + + Parameters + ---------- + self: array + array instance. + api_version: Optional[str] + string representing the version of the array API specification to be returned, in ``'YYYY.MM'`` form, for example, ``'2020.10'``. If it is ``None``, it should return the namespace corresponding to latest version of the array API specification. If the given version is invalid or not implemented for the given module, an error should be raised. Default: ``None``. + + Returns + ------- + out: Any + an object representing the array API namespace. It should have every top-level function defined in the specification as an attribute. It may contain other public names as well, but it is recommended to only include those names that are part of the specification. + """ + + def __bool__(self: array, /) -> bool: + """ + Converts a zero-dimensional array to a Python ``bool`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: bool + a Python ``bool`` object representing the single element of the array. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``True``. + - If ``self`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - If ``self`` is either ``+0`` or ``-0``, the result is ``False``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as the logical OR of ``bool(real(self))`` and ``bool(imag(self))``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``bool``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __complex__(self: array, /) -> complex: + """ + Converts a zero-dimensional array to a Python ``complex`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. + + Returns + ------- + out: complex + a Python ``complex`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1+0j``. + - If ``self`` is ``False``, the result is ``0+0j``. + + For real-valued floating-point operands, + + - If ``self`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``self`` is ``+infinity``, the result is ``+infinity + 0j``. + - If ``self`` is ``-infinity``, the result is ``-infinity + 0j``. + - If ``self`` is a finite number, the result is ``self + 0j``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``complex``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __dlpack__( + self: array, + /, + *, + stream: Optional[Union[int, Any]] = None, + max_version: Optional[tuple[int, int]] = None, + dl_device: Optional[tuple[Enum, int]] = None, + copy: Optional[bool] = None, + ) -> PyCapsule: + """ + Exports the array for consumption by :func:`~array_api.from_dlpack` as a DLPack capsule. + + Parameters + ---------- + self: array + array instance. + stream: Optional[Union[int, Any]] + for CUDA and ROCm, a Python integer representing a pointer to a stream, on devices that support streams. ``stream`` is provided by the consumer to the producer to instruct the producer to ensure that operations can safely be performed on the array (e.g., by inserting a dependency between streams via "wait for event"). The pointer must be an integer larger than or equal to ``-1`` (see below for allowed values on each platform). If ``stream`` is ``-1``, the value may be used by the consumer to signal "producer must not perform any synchronization". The ownership of the stream stays with the consumer. On CPU and other device types without streams, only ``None`` is accepted. + + For other device types which do have a stream, queue, or similar synchronization/ordering mechanism, the most appropriate type to use for ``stream`` is not yet determined. E.g., for SYCL one may want to use an object containing an in-order ``cl::sycl::queue``. This is allowed when libraries agree on such a convention, and may be standardized in a future version of this API standard. + + .. note:: + Support for a ``stream`` value other than ``None`` is optional and implementation-dependent. + + Device-specific values of ``stream`` for CUDA: + + - ``None``: producer must assume the legacy default stream (default). + - ``1``: the legacy default stream. + - ``2``: the per-thread default stream. + - ``> 2``: stream number represented as a Python integer. + - ``0`` is disallowed due to its ambiguity: ``0`` could mean either ``None``, ``1``, or ``2``. + + Device-specific values of ``stream`` for ROCm: + + - ``None``: producer must assume the legacy default stream (default). + - ``0``: the default stream. + - ``> 2``: stream number represented as a Python integer. + - Using ``1`` and ``2`` is not supported. + + .. note:: + When ``dl_device`` is provided explicitly, ``stream`` must be a valid + construct for the specified device type. In particular, when ``kDLCPU`` + is in use, ``stream`` must be ``None`` and a synchronization must be + performed to ensure data safety. + + .. admonition:: Tip + :class: important + + It is recommended that implementers explicitly handle streams. If + they use the legacy default stream, specifying ``1`` (CUDA) or ``0`` + (ROCm) is preferred. ``None`` is a safe default for developers who do + not want to think about stream handling at all, potentially at the + cost of more synchronizations than necessary. + max_version: Optional[tuple[int, int]] + the maximum DLPack version that the *consumer* (i.e., the caller of + ``__dlpack__``) supports, in the form of a 2-tuple ``(major, minor)``. + This method may return a capsule of version ``max_version`` (recommended + if it does support that), or of a different version. + This means the consumer must verify the version even when + `max_version` is passed. + dl_device: Optional[tuple[enum.Enum, int]] + the DLPack device type. Default is ``None``, meaning the exported capsule + should be on the same device as ``self`` is. When specified, the format + must be a 2-tuple, following that of the return value of :meth:`array.__dlpack_device__`. + If the device type cannot be handled by the producer, this function must + raise ``BufferError``. + + The v2023.12 standard only mandates that a compliant library should offer a way for + ``__dlpack__`` to return a capsule referencing an array whose underlying memory is + accessible to the Python interpreter (represented by the ``kDLCPU`` enumerator in DLPack). + If a copy must be made to enable this support but ``copy`` is set to ``False``, the + function must raise ``BufferError``. + + Other device kinds will be considered for standardization in a future version of this + API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the + function must always copy (performed by the producer; see also :ref:`copy-keyword-argument`). If ``False``, the + function must never copy, and raise a ``BufferError`` in case a copy is + deemed necessary (e.g. if a cross-device data movement is requested, and + it is not possible without a copy). If ``None``, the function must reuse + the existing memory buffer if possible and copy otherwise. Default: ``None``. + + When a copy happens, the ``DLPACK_FLAG_BITMASK_IS_COPIED`` flag must be set. + + .. note:: + If a copy happens, and if the consumer-provided ``stream`` and ``dl_device`` + can be understood by the producer, the copy must be performed over ``stream``. + + Returns + ------- + capsule: PyCapsule + a DLPack capsule for the array. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + Implementations should raise ``BufferError`` when the data cannot + be exported as DLPack (e.g., incompatible dtype or strides). Other + errors are raised when export fails for other reasons (e.g., incorrect + arguments passed or out of memory). + + Notes + ----- + The DLPack version scheme is SemVer, where the major DLPack versions + represent ABI breaks, and minor versions represent ABI-compatible additions + (e.g., new enum values for new data types or device types). + + The ``max_version`` keyword was introduced in v2023.12, and goes + together with the ``DLManagedTensorVersioned`` struct added in DLPack + 1.0. This keyword may not be used by consumers until a later time after + introduction, because producers may implement the support at a different + point in time. + + It is recommended for the producer to use this logic in the implementation + of ``__dlpack__``: + + .. code:: python + + if max_version is None: + # Keep and use the DLPack 0.X implementation + # Note: from March 2025 onwards (but ideally as late as + # possible), it's okay to raise BufferError here + else: + # We get to produce `DLManagedTensorVersioned` now. Note that + # our_own_dlpack_version is the max version that the *producer* + # supports and fills in the `DLManagedTensorVersioned::version` + # field + if max_version >= our_own_dlpack_version: + # Consumer understands us, just return a Capsule with our max version + elif max_version[0] == our_own_dlpack_version[0]: + # major versions match, we should still be fine here - + # return our own max version + else: + # if we're at a higher major version internally, did we + # keep an implementation of the older major version around? + # For example, if the producer is on DLPack 1.x and the consumer + # is 0.y, can the producer still export a capsule containing + # DLManagedTensor and not DLManagedTensorVersioned? + # If so, use that. Else, the producer should raise a BufferError + # here to tell users that the consumer's max_version is too + # old to allow the data exchange to happen. + + And this logic for the consumer in :func:`~array_api.from_dlpack`: + + .. code:: python + + try: + x.__dlpack__(max_version=(1, 0), ...) + # if it succeeds, store info from the capsule named "dltensor_versioned", + # and need to set the name to "used_dltensor_versioned" when we're done + except TypeError: + x.__dlpack__(...) + + This logic is also applicable to handling of the new ``dl_device`` and ``copy`` + keywords. + + DLPack 1.0 added a flag to indicate that the array is read-only + (``DLPACK_FLAG_BITMASK_READ_ONLY``). A consumer that does not support + read-only arrays should ignore this flag (this is preferred over + raising an exception; the user is then responsible for ensuring the + memory isn't modified). + + .. versionchanged:: 2022.12 + Added BufferError. + + .. versionchanged:: 2023.12 + Added the ``max_version``, ``dl_device``, and ``copy`` keyword arguments. + + .. versionchanged:: 2023.12 + Added recommendation for handling read-only arrays. + + .. versionchanged:: 2024.12 + Resolved conflicting exception guidance. + """ + + def __dlpack_device__(self: array, /) -> Tuple[Enum, int]: + """ + Returns device type and device ID in DLPack format. Meant for use within :func:`~array_api.from_dlpack`. + + Parameters + ---------- + self: array + array instance. + + Returns + ------- + device: Tuple[Enum, int] + a tuple ``(device_type, device_id)`` in DLPack format. Valid device type enum members are: + + :: + + CPU = 1 + CUDA = 2 + CPU_PINNED = 3 + OPENCL = 4 + VULKAN = 7 + METAL = 8 + VPI = 9 + ROCM = 10 + CUDA_MANAGED = 13 + ONE_API = 14 + """ + + def __eq__(self: array, other: Union[int, float, complex, bool, array], /) -> array: + r""" + Computes the truth value of ``self_i == other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, complex, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __float__(self: array, /) -> float: + """ + Converts a zero-dimensional array to a Python ``float`` object. + + .. note:: + Casting integer values outside the representable bounds of Python's float type is not specified and is implementation-dependent. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: float + a Python ``float`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + **Lazy implementations** + + The Python language requires the return value to be of type ``float``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __floordiv__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i // other_i`` for each element of an array instance with the respective element of the array ``other``. + + .. note:: + For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + + .. note:: + Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.floor_divide`. + """ + + def __ge__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i >= other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __getitem__( + self: array, + key: Union[ + int, + slice, + ellipsis, + None, + Tuple[Union[int, slice, ellipsis, array, None], ...], + array, + ], + /, + ) -> array: + """ + Returns ``self[key]``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, None, Tuple[Union[int, slice, ellipsis, array, None], ...], array] + index key. + + Returns + ------- + out: array + an array containing the accessed value(s). The returned array must have the same data type as ``self``. + + Notes + ----- + + - See :ref:`indexing` for details on supported indexing semantics. + - When ``__getitem__`` is defined on an object, Python will automatically define iteration (i.e., the behavior from ``iter(x)``) as ``x[0]``, ``x[1]``, ..., ``x[N-1]``. This can also be implemented directly by defining ``__iter__``. Therefore, for a one-dimensional array ``x``, iteration should produce a sequence of zero-dimensional arrays ``x[0]``, ``x[1]``, ..., ``x[N-1]``, where ``N`` is the number of elements in the array. Iteration behavior for arrays having zero dimensions or more than one dimension is unspecified and thus implementation-defined. + + .. versionchanged:: 2024.12 + Clarified that iteration is defined for one-dimensional arrays. + """ + + def __gt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i > other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.greater`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __index__(self: array, /) -> int: + """ + Converts a zero-dimensional integer array to a Python ``int`` object. + + .. note:: + This method is called to implement `operator.index() `_. See also `PEP 357 `_. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have an integer data type. If ``self`` has a floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __int__(self: array, /) -> int: + """ + Converts a zero-dimensional array to a Python ``int`` object. + + Parameters + ---------- + self: array + zero-dimensional array instance. Should have a real-valued or boolean data type. If ``self`` has a complex floating-point data type, the function must raise a ``TypeError``. + + Returns + ------- + out: int + a Python ``int`` object representing the single element of the array instance. + + Notes + ----- + + **Special cases** + + For boolean operands, + + - If ``self`` is ``True``, the result is ``1``. + - If ``self`` is ``False``, the result is ``0``. + + For floating-point operands, + + - If ``self`` is a finite number, the result is the integer part of ``self``. + - If ``self`` is ``-0``, the result is ``0``. + + **Raises** + + For floating-point operands, + + - If ``self`` is either ``+infinity`` or ``-infinity``, raise ``OverflowError``. + - If ``self`` is ``NaN``, raise ``ValueError``. + + Notes + ----- + + **Lazy implementations** + + The Python language requires the return value to be of type ``int``. Lazy implementations are therefore not able to return any kind of lazy/delayed object here and should raise a ``ValueError`` instead. + + .. versionchanged:: 2022.12 + Added boolean and complex data type support. + + .. versionchanged:: 2023.12 + Allowed lazy implementations to error. + """ + + def __invert__(self: array, /) -> array: + """ + Evaluates ``~self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as `self`. + + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_invert`. + """ + + def __le__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i <= other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __lshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i << other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_left_shift`. + """ + + def __lt__(self: array, other: Union[int, float, array], /) -> array: + """ + Computes the truth value of ``self_i < other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.less`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __matmul__(self: array, other: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. Must have at least one dimension. If ``self`` is one-dimensional having shape ``(M,)`` and ``other`` has more than one dimension, ``self`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``self`` has more than one dimension (including after vector-to-matrix promotion), ``shape(self)[:-2]`` must be compatible with ``shape(other)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``self`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + other: array + other array. Should have a numeric data type. Must have at least one dimension. If ``other`` is one-dimensional having shape ``(N,)`` and ``self`` has more than one dimension, ``other`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``other`` has more than one dimension (including after vector-to-matrix promotion), ``shape(other)[:-2]`` must be compatible with ``shape(self)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``other`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``self`` and ``other`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``self`` is a one-dimensional array having shape ``(K,)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``self`` is a two-dimensional array having shape ``(M, K)`` and ``other`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``self`` is an array having shape ``(..., M, K)`` and ``other`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``self`` or ``other`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(self)[:-2]`` against ``shape(other)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + - The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Results must equal the results returned by the equivalent function :func:`~array_api.matmul`. + + **Raises** + + - if either ``self`` or ``other`` is a zero-dimensional array. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is a one-dimensional array having shape ``(K,)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``self`` is an array having shape ``(..., M, K)``, ``other`` is an array having shape ``(..., L, N)``, and ``K != L``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __mod__(self: array, other: Union[int, float, array], /) -> array: + """ + Evaluates ``self_i % other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a real-valued data type. + other: Union[int, float, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``other_i``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.remainder`. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + """ + + def __mul__(self: array, other: Union[int, float, complex, array], /) -> array: + r""" + Calculates the product for each element of an array instance with the respective element of the array ``other``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, complex, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __ne__(self: array, other: Union[int, float, complex, bool, array], /) -> array: + """ + Computes the truth value of ``self_i != other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. May have any data type. + other: Union[int, float, complex, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool`` (i.e., must be a boolean array). + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.not_equal`. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + """ + + def __neg__(self: array, /) -> array: + """ + Evaluates ``-self_i`` for each element of an array instance. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``self`` has a complex floating-point data type, both the real and imaginary components for each ``self_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``self``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.negative`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __or__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i | other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_or`. + """ + + def __pos__(self: array, /) -> array: + """ + Evaluates ``+self_i`` for each element of an array instance. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element. The returned array must have the same data type as ``self``. + + Notes + ----- + + .. note:: + Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.positive`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __pow__(self: array, other: Union[int, float, complex, array], /) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element (the base) of an array instance to the power of ``other_i`` (the exponent), where ``other_i`` is the corresponding element of the array ``other``. + + Parameters + ---------- + self: array + array instance whose elements correspond to the exponentiation base. Should have a numeric data type. + other: Union[int, float, complex, array] + other array whose elements correspond to the exponentiation exponent. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.pow`. + - If both ``self`` and ``other`` have integer data types, the result of ``__pow__`` when `other_i` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + - If ``self`` has an integer data type and ``other`` has a floating-point data type, behavior is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __rshift__(self: array, other: Union[int, array], /) -> array: + """ + Evaluates ``self_i >> other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer data type. + other: Union[int, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``self``. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_right_shift`. + """ + + def __setitem__( + self: array, + key: Union[ + int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array + ], + value: Union[int, float, complex, bool, array], + /, + ) -> None: + """ + Sets ``self[key]`` to ``value``. + + Parameters + ---------- + self: array + array instance. + key: Union[int, slice, ellipsis, Tuple[Union[int, slice, ellipsis, array], ...], array] + index key. + value: Union[int, float, complex, bool, array] + value(s) to set. Must be compatible with ``self[key]`` (see :ref:`broadcasting`). + + Notes + ----- + + - See :ref:`indexing` for details on supported indexing semantics. + + .. note:: + Indexing semantics when ``key`` is an integer array or a tuple of integers and integer arrays is currently unspecified and thus implementation-defined. This will be revisited in a future revision of this standard. + + - Setting array values must not affect the data type of ``self``. + - When ``value`` is a Python scalar (i.e., ``int``, ``float``, ``complex``, ``bool``), behavior must follow specification guidance on mixing arrays with Python scalars (see :ref:`type-promotion`). + - When ``value`` is an ``array`` of a different data type than ``self``, how values are cast to the data type of ``self`` is implementation defined. + """ + + def __sub__(self: array, other: Union[int, float, complex, array], /) -> array: + """ + Calculates the difference for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance (minuend array). Should have a numeric data type. + other: Union[int, float, complex, array] + subtrahend array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.subtract`. + - The result of ``self_i - other_i`` must be the same as ``self_i + (-other_i)`` and must be governed by the same floating-point rules as addition (see :meth:`array.__add__`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __truediv__(self: array, other: Union[int, float, complex, array], /) -> array: + r""" + Evaluates ``self_i / other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have a numeric data type. + other: Union[int, float, complex, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array should have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results, including special cases, must equal the results returned by the equivalent element-wise function :func:`~array_api.divide`. + + - If one or both of ``self`` and ``other`` have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + def __xor__(self: array, other: Union[int, bool, array], /) -> array: + """ + Evaluates ``self_i ^ other_i`` for each element of an array instance with the respective element of the array ``other``. + + Parameters + ---------- + self: array + array instance. Should have an integer or boolean data type. + other: Union[int, bool, array] + other array. Must be compatible with ``self`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - Element-wise results must equal the results returned by the equivalent element-wise function :func:`~array_api.bitwise_xor`. + """ + + def to_device( + self: array, device: Device, /, *, stream: Optional[Union[int, Any]] = None + ) -> array: + """ + Copy the array from the device on which it currently resides to the specified ``device``. + + Parameters + ---------- + self: array + array instance. + device: device + a ``device`` object (see :ref:`device-support`). + stream: Optional[Union[int, Any]] + stream object to use during copy. In addition to the types supported in :meth:`array.__dlpack__`, implementations may choose to support any library-specific stream object with the caveat that any code using such an object would not be portable. + + Returns + ------- + out: array + an array with the same data and data type as ``self`` and located on the specified ``device``. + + + Notes + ----- + + - When a provided ``device`` object corresponds to the same device on which an array instance resides, implementations may choose to perform an explicit copy or return ``self``. + - If ``stream`` is provided, the copy operation should be enqueued on the provided ``stream``; otherwise, the copy operation should be enqueued on the default stream/queue. Whether the copy is performed synchronously or asynchronously is implementation-dependent. Accordingly, if synchronization is required to guarantee data safety, this must be clearly explained in a conforming array library's documentation. + + .. versionchanged:: 2023.12 + Clarified behavior when a provided ``device`` object corresponds to the device on which an array instance resides. + """ + + +array = _array diff --git a/src/array_api_stubs/_2024_12/constants.py b/src/array_api_stubs/_2024_12/constants.py new file mode 100644 index 000000000..c5735d09f --- /dev/null +++ b/src/array_api_stubs/_2024_12/constants.py @@ -0,0 +1,30 @@ +__all__ = ["e", "inf", "nan", "newaxis", "pi"] + +e = 2.718281828459045 +""" +IEEE 754 floating-point representation of Euler's constant. + +``e = 2.71828182845904523536028747135266249775724709369995...`` +""" + +inf = float("inf") +""" +IEEE 754 floating-point representation of (positive) infinity. +""" + +nan = float("nan") +""" +IEEE 754 floating-point representation of Not a Number (``NaN``). +""" + +newaxis = None +""" +An alias for ``None`` which is useful for indexing arrays. +""" + +pi = 3.141592653589793 +""" +IEEE 754 floating-point representation of the mathematical constant ``π``. + +``pi = 3.1415926535897932384626433...`` +""" diff --git a/src/array_api_stubs/_2024_12/creation_functions.py b/src/array_api_stubs/_2024_12/creation_functions.py new file mode 100644 index 000000000..c09800783 --- /dev/null +++ b/src/array_api_stubs/_2024_12/creation_functions.py @@ -0,0 +1,647 @@ +__all__ = [ + "arange", + "asarray", + "empty", + "empty_like", + "eye", + "from_dlpack", + "full", + "full_like", + "linspace", + "meshgrid", + "ones", + "ones_like", + "tril", + "triu", + "zeros", + "zeros_like", +] + + +from ._types import ( + List, + NestedSequence, + Optional, + SupportsBufferProtocol, + Tuple, + Union, + array, + device, + dtype, +) + + +def arange( + start: Union[int, float], + /, + stop: Optional[Union[int, float]] = None, + step: Union[int, float] = 1, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns evenly spaced values within the half-open interval ``[start, stop)`` as a one-dimensional array. + + Parameters + ---------- + start: Union[int, float] + if ``stop`` is specified, the start of interval (inclusive); otherwise, the end of the interval (exclusive). If ``stop`` is not specified, the default starting value is ``0``. + stop: Optional[Union[int, float]] + the end of the interval. Default: ``None``. + step: Union[int, float] + the distance between two adjacent elements (``out[i+1] - out[i]``). Must not be ``0``; may be negative, this results in an empty array if ``stop >= start``. Default: ``1``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``start``, ``stop`` and ``step``. If those are all integers, the output array dtype must be the default integer dtype; if one or more have type ``float``, then the output array dtype must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + + .. note:: + This function cannot guarantee that the interval does not include the ``stop`` value in those cases where ``step`` is not an integer and floating-point rounding errors affect the length of the output array. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. The length of the output array must be ``ceil((stop-start)/step)`` if ``stop - start`` and ``step`` have the same sign, and length ``0`` otherwise. + """ + + +def asarray( + obj: Union[ + array, bool, int, float, complex, NestedSequence, SupportsBufferProtocol + ], + /, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + r""" + Convert the input to an array. + + Parameters + ---------- + obj: Union[array, bool, int, float, complex, NestedSequence[bool | int | float | complex], SupportsBufferProtocol] + object to be converted to an array. May be a Python scalar, a (possibly nested) sequence of Python scalars, or an object supporting the Python buffer protocol. + + .. admonition:: Tip + :class: important + + An object supporting the buffer protocol can be turned into a memoryview through ``memoryview(obj)``. + + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from the data type(s) in ``obj``. If all input values are Python scalars, then, in order of precedence, + + - if all values are of type ``bool``, the output data type must be ``bool``. + - if all values are of type ``int`` or are a mixture of ``bool`` and ``int``, the output data type must be the default integer data type. + - if one or more values are ``complex`` numbers, the output data type must be the default complex floating-point data type. + - if one or more values are ``float``\s, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, then array conversions should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. To perform an explicit cast, use :func:`array_api.astype`. + + .. note:: + If an input value exceeds the precision of the resolved output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``obj`` is an array, the output array device must be inferred from ``obj``. Default: ``None``. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy for input which supports the buffer protocol and must raise a ``ValueError`` in case a copy would be necessary. If ``None``, the function must reuse existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data from ``obj``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def empty( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns an uninitialized array having a specified `shape`. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing uninitialized data. + """ + + +def empty_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns an uninitialized array with the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and containing uninitialized data. + """ + + +def eye( + n_rows: int, + n_cols: Optional[int] = None, + /, + *, + k: int = 0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + r""" + Returns a two-dimensional array with ones on the ``k``\th diagonal and zeros elsewhere. + + .. note:: + An output array having a complex floating-point data type must have the value ``1 + 0j`` along the ``k``\th diagonal and ``0 + 0j`` elsewhere. + + Parameters + ---------- + n_rows: int + number of rows in the output array. + n_cols: Optional[int] + number of columns in the output array. If ``None``, the default number of columns in the output array is equal to ``n_rows``. Default: ``None``. + k: int + index of the diagonal. A positive value refers to an upper diagonal, a negative value to a lower diagonal, and ``0`` to the main diagonal. Default: ``0``. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where all elements are equal to zero, except for the ``k``\th diagonal, whose values are equal to one. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def from_dlpack( + x: object, + /, + *, + device: Optional[device] = None, + copy: Optional[bool] = None, +) -> array: + """ + Returns a new array containing the data from another (array) object with a ``__dlpack__`` method. + + Parameters + ---------- + x: object + input (array) object. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None`` and ``x`` supports DLPack, the output array must be on the same device as ``x``. Default: ``None``. + + The v2023.12 standard only mandates that a compliant library should offer a way for ``from_dlpack`` to return an array + whose underlying memory is accessible to the Python interpreter, when the corresponding ``device`` is provided. If the + array library does not support such cases at all, the function must raise ``BufferError``. If a copy must be made to + enable this support but ``copy`` is set to ``False``, the function must raise ``ValueError``. + + Other device kinds will be considered for standardization in a future version of this API standard. + copy: Optional[bool] + boolean indicating whether or not to copy the input. If ``True``, the function must always copy. If ``False``, the function must never copy, and raise ``BufferError`` in case a copy is deemed necessary (e.g. if a cross-device data movement is requested, and it is not possible without a copy). If ``None``, the function must reuse the existing memory buffer if possible and copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an array containing the data in ``x``. + + .. admonition:: Note + :class: note + + The returned array may be either a copy or a view. See :ref:`data-interchange` for details. + + Raises + ------ + BufferError + The ``__dlpack__`` and ``__dlpack_device__`` methods on the input array + may raise ``BufferError`` when the data cannot be exported as DLPack + (e.g., incompatible dtype, strides, or device). It may also raise other errors + when export fails for other reasons (e.g., not enough memory available + to materialize the data). ``from_dlpack`` must propagate such + exceptions. + AttributeError + If the ``__dlpack__`` and ``__dlpack_device__`` methods are not present + on the input array. This may happen for libraries that are never able + to export their data with DLPack. + ValueError + If data exchange is possible via an explicit copy but ``copy`` is set to ``False``. + + Notes + ----- + See :meth:`array.__dlpack__` for implementation suggestions for `from_dlpack` in + order to handle DLPack versioning correctly. + + A way to move data from two array libraries to the same device (assumed supported by both libraries) in + a library-agnostic fashion is illustrated below: + + .. code:: python + + def func(x, y): + xp_x = x.__array_namespace__() + xp_y = y.__array_namespace__() + + # Other functions than `from_dlpack` only work if both arrays are from the same library. So if + # `y` is from a different one than `x`, let's convert `y` into an array of the same type as `x`: + if not xp_x == xp_y: + y = xp_x.from_dlpack(y, copy=True, device=x.device) + + # From now on use `xp_x.xxxxx` functions, as both arrays are from the library `xp_x` + ... + + + .. versionchanged:: 2023.12 + Required exceptions to address unsupported use cases. + + .. versionchanged:: 2023.12 + Added device and copy support. + """ + + +def full( + shape: Union[int, Tuple[int, ...]], + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ``fill_value``. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``fill_value`` according to the following rules: + + - If the fill value is an ``int``, the output array data type must be the default integer data type. + - If the fill value is a ``float``, the output array data type must be the default real-valued floating-point data type. + - If the fill value is a ``complex`` number, the output array data type must be the default complex floating-point data type. + - If the fill value is a ``bool``, the output array must have a boolean data type. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved default output array data type, behavior is left unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def full_like( + x: array, + /, + fill_value: Union[bool, int, float, complex], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array filled with ``fill_value`` and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + fill_value: Union[bool, int, float, complex] + fill value. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + + .. note:: + If the ``fill_value`` exceeds the precision of the resolved output array data type, behavior is unspecified and, thus, implementation-defined. + + .. note:: + If the ``fill_value`` has a data type which is not of the same data type kind (boolean, integer, or floating-point) as the resolved output array data type (see :ref:`type-promotion`), behavior is unspecified and, thus, implementation-defined. + + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and where every element is equal to ``fill_value``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def linspace( + start: Union[int, float, complex], + stop: Union[int, float, complex], + /, + num: int, + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, + endpoint: bool = True, +) -> array: + r""" + Returns evenly spaced numbers over a specified interval. + + Let :math:`N` be the number of generated values (which is either ``num`` or ``num+1`` depending on whether ``endpoint`` is ``True`` or ``False``, respectively). For real-valued output arrays, the spacing between values is given by + + .. math:: + \Delta_{\textrm{real}} = \frac{\textrm{stop} - \textrm{start}}{N - 1} + + For complex output arrays, let ``a = real(start)``, ``b = imag(start)``, ``c = real(stop)``, and ``d = imag(stop)``. The spacing between complex values is given by + + .. math:: + \Delta_{\textrm{complex}} = \frac{c-a}{N-1} + \frac{d-b}{N-1} j + + Parameters + ---------- + start: Union[int, float, complex] + the start of the interval. + stop: Union[int, float, complex] + the end of the interval. If ``endpoint`` is ``False``, the function must generate a sequence of ``num+1`` evenly spaced numbers starting with ``start`` and ending with ``stop`` and exclude the ``stop`` from the returned array such that the returned array consists of evenly spaced numbers over the half-open interval ``[start, stop)``. If ``endpoint`` is ``True``, the output array must consist of evenly spaced numbers over the closed interval ``[start, stop]``. Default: ``True``. + + .. note:: + The step size changes when `endpoint` is `False`. + + num: int + number of samples. Must be a nonnegative integer value. + dtype: Optional[dtype] + output array data type. Should be a floating-point data type. If ``dtype`` is ``None``, + + - if either ``start`` or ``stop`` is a ``complex`` number, the output data type must be the default complex floating-point data type. + - if both ``start`` and ``stop`` are real-valued, the output data type must be the default real-valued floating-point data type. + + Default: ``None``. + + .. admonition:: Note + :class: note + + If ``dtype`` is not ``None``, conversion of ``start`` and ``stop`` should obey :ref:`type-promotion` rules. Conversions not specified according to :ref:`type-promotion` rules may or may not be permitted by a conforming array library. + + device: Optional[device] + device on which to place the created array. Default: ``None``. + endpoint: bool + boolean indicating whether to include ``stop`` in the interval. Default: ``True``. + + Returns + ------- + out: array + a one-dimensional array containing evenly spaced values. + + Notes + ----- + + .. note:: + While this specification recommends that this function only return arrays having a floating-point data type, specification-compliant array libraries may choose to support output arrays having an integer data type (e.g., due to backward compatibility concerns). However, function behavior when generating integer output arrays is unspecified and, thus, is implementation-defined. Accordingly, using this function to generate integer output arrays is not portable. + + .. note:: + As mixed data type promotion is implementation-defined, behavior when ``start`` or ``stop`` exceeds the maximum safe integer of an output floating-point data type is implementation-defined. An implementation may choose to overflow or raise an exception. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: + """ + Returns coordinate matrices from coordinate vectors. + + Parameters + ---------- + arrays: array + an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. + indexing: str + Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. + + Returns + ------- + out: List[array] + list of N arrays, where ``N`` is the number of provided one-dimensional input arrays. Each returned array must have rank ``N``. For ``N`` one-dimensional arrays having lengths ``Ni = len(xi)``, + + - if matrix indexing ``ij``, then each returned array must have the shape ``(N1, N2, N3, ..., Nn)``. + - if Cartesian indexing ``xy``, then each returned array must have shape ``(N2, N1, N3, ..., Nn)``. + + Accordingly, for the two-dimensional case with input one-dimensional arrays of length ``M`` and ``N``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M)``. + + Similarly, for the three-dimensional case with input one-dimensional arrays of length ``M``, ``N``, and ``P``, if matrix indexing ``ij``, then each returned array must have shape ``(M, N, P)``, and, if Cartesian indexing ``xy``, then each returned array must have shape ``(N, M, P)``. + + Each returned array should have the same data type as the input arrays. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with ones. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def ones_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with ones and having the same ``shape`` as an input array ``x``. + + .. note:: + An output array having a complex floating-point data type must contain complex numbers having a real component equal to one and an imaginary component equal to zero (i.e., ``1 + 0j``). + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with ones. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tril(x: array, /, *, k: int = 0) -> array: + """ + Returns the lower triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The lower triangular part of the matrix is defined as the elements on and below the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal above which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the lower triangular part(s). The returned array must have the same shape and data type as ``x``. All elements above the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def triu(x: array, /, *, k: int = 0) -> array: + """ + Returns the upper triangular part of a matrix (or a stack of matrices) ``x``. + + .. note:: + The upper triangular part of the matrix is defined as the elements on and above the specified diagonal ``k``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + k: int + diagonal below which to zero elements. If ``k = 0``, the diagonal is the main diagonal. If ``k < 0``, the diagonal is below the main diagonal. If ``k > 0``, the diagonal is above the main diagonal. Default: ``0``. + + .. note:: + The main diagonal is defined as the set of indices ``{(i, i)}`` for ``i`` on the interval ``[0, min(M, N) - 1]``. + + Returns + ------- + out: array + an array containing the upper triangular part(s). The returned array must have the same shape and data type as ``x``. All elements below the specified diagonal ``k`` must be zeroed. The returned array should be allocated on the same device as ``x``. + """ + + +def zeros( + shape: Union[int, Tuple[int, ...]], + *, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Returns a new array having a specified ``shape`` and filled with zeros. + + Parameters + ---------- + shape: Union[int, Tuple[int, ...]] + output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array containing zeros. + """ + + +def zeros_like( + x: array, /, *, dtype: Optional[dtype] = None, device: Optional[device] = None +) -> array: + """ + Returns a new array filled with zeros and having the same ``shape`` as an input array ``x``. + + Parameters + ---------- + x: array + input array from which to derive the output array shape. + dtype: Optional[dtype] + output array data type. If ``dtype`` is ``None``, the output array data type must be inferred from ``x``. Default: ``None``. + device: Optional[device] + device on which to place the created array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the same shape as ``x`` and filled with zeros. + """ diff --git a/src/array_api_stubs/_2024_12/data_type_functions.py b/src/array_api_stubs/_2024_12/data_type_functions.py new file mode 100644 index 000000000..7a6c59d94 --- /dev/null +++ b/src/array_api_stubs/_2024_12/data_type_functions.py @@ -0,0 +1,250 @@ +__all__ = ["astype", "can_cast", "finfo", "iinfo", "isdtype", "result_type"] + +from ._types import ( + Union, + Tuple, + array, + dtype, + finfo_object, + iinfo_object, + device, + Optional, +) + + +def astype( + x: array, dtype: dtype, /, *, copy: bool = True, device: Optional[device] = None +) -> array: + """ + Copies an array to a specified data type irrespective of :ref:`type-promotion` rules. + + .. note:: + Casting floating-point ``NaN`` and ``infinity`` values to integral data types is not specified and is implementation-dependent. + + .. note:: + Casting a complex floating-point array to a real-valued data type should not be permitted. + + Historically, when casting a complex floating-point array to a real-valued data type, libraries such as NumPy have discarded imaginary components such that, for a complex floating-point array ``x``, ``astype(x)`` equals ``astype(real(x))``). This behavior is considered problematic as the choice to discard the imaginary component is arbitrary and introduces more than one way to achieve the same outcome (i.e., for a complex floating-point array ``x``, ``astype(x)`` and ``astype(real(x))`` versus only ``astype(imag(x))``). Instead, in order to avoid ambiguity and to promote clarity, this specification requires that array API consumers explicitly express which component should be cast to a specified real-valued data type. + + .. note:: + When casting a boolean input array to a real-valued data type, a value of ``True`` must cast to a real-valued number equal to ``1``, and a value of ``False`` must cast to a real-valued number equal to ``0``. + + When casting a boolean input array to a complex floating-point data type, a value of ``True`` must cast to a complex number equal to ``1 + 0j``, and a value of ``False`` must cast to a complex number equal to ``0 + 0j``. + + .. note:: + When casting a real-valued input array to ``bool``, a value of ``0`` must cast to ``False``, and a non-zero value must cast to ``True``. + + When casting a complex floating-point array to ``bool``, a value of ``0 + 0j`` must cast to ``False``, and all other values must cast to ``True``. + + Parameters + ---------- + x: array + array to cast. + dtype: dtype + desired data type. + copy: bool + specifies whether to copy an array when the specified ``dtype`` matches the data type of the input array ``x``. If ``True``, a newly allocated array must always be returned (see :ref:`copy-keyword-argument`). If ``False`` and the specified ``dtype`` matches the data type of the input array, the input array must be returned; otherwise, a newly allocated array must be returned. Default: ``True``. + device: Optional[device] + device on which to place the returned array. If ``device`` is ``None``, the output array device must be inferred from ``x``. Default: ``None``. + + Returns + ------- + out: array + an array having the specified data type. The returned array must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Added device keyword argument support. + """ + + +def can_cast(from_: Union[dtype, array], to: dtype, /) -> bool: + """ + Determines if one data type can be cast to another data type according to type promotion rules (see :ref:`type-promotion`). + + Parameters + ---------- + from_: Union[dtype, array] + input data type or array from which to cast. + to: dtype + desired data type. + + Returns + ------- + out: bool + ``True`` if the cast can occur according to type promotion rules (see :ref:`type-promotion`); otherwise, ``False``. + + Notes + ----- + + - When ``from_`` is a data type, the function must determine whether the data type can be cast to another data type according to the complete type promotion rules (see :ref:`type-promotion`) described in this specification, irrespective of whether a conforming array library supports devices which do not have full data type support. + - When ``from_`` is an array, the function must determine whether the data type of the array can be cast to the desired data type according to the type promotion graph of the array device. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the output of ``can_cast(array, dtype)`` may differ from ``can_cast(array.dtype, dtype)``. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. + """ + + +def finfo(type: Union[dtype, array], /) -> finfo_object: + """ + Machine limits for floating-point data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of floating-point data-type about which to get information. If complex, the information is about its component data type. + + .. note:: + Complex floating-point data types are specified to always use the same precision for both its real and imaginary components, so the information should be true for either component. + + Returns + ------- + out: finfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the real-valued floating-point data type. + + - **eps**: *float* + + difference between 1.0 and the next smallest representable real-valued floating-point number larger than 1.0 according to the IEEE-754 standard. + + - **max**: *float* + + largest representable real-valued number. + + - **min**: *float* + + smallest representable real-valued number. + + - **smallest_normal**: *float* + + smallest positive real-valued floating-point number with full precision. + + - **dtype**: dtype + + real-valued floating-point data type. + + .. versionadded:: 2022.12 + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def iinfo(type: Union[dtype, array], /) -> iinfo_object: + """ + Machine limits for integer data types. + + Parameters + ---------- + type: Union[dtype, array] + the kind of integer data-type about which to get information. + + Returns + ------- + out: iinfo object + an object having the following attributes: + + - **bits**: *int* + + number of bits occupied by the type. + + - **max**: *int* + + largest representable number. + + - **min**: *int* + + smallest representable number. + + - **dtype**: dtype + + integer data type. + + .. versionadded:: 2022.12 + """ + + +def isdtype( + dtype: dtype, kind: Union[dtype, str, Tuple[Union[dtype, str], ...]] +) -> bool: + """ + Returns a boolean indicating whether a provided dtype is of a specified data type "kind". + + Parameters + ---------- + dtype: dtype + the input dtype. + kind: Union[str, dtype, Tuple[Union[str, dtype], ...]] + data type kind. + + - If ``kind`` is a dtype, the function must return a boolean indicating whether the input ``dtype`` is equal to the dtype specified by ``kind``. + - If ``kind`` is a string, the function must return a boolean indicating whether the input ``dtype`` is of a specified data type kind. The following dtype kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of dtypes and/or kinds, and the function must return a boolean indicating whether the input ``dtype`` is either equal to a specified dtype or belongs to at least one specified data type kind. + + .. note:: + A conforming implementation of the array API standard is **not** limited to only including the dtypes described in this specification in the required data type kinds. For example, implementations supporting ``float16`` and ``bfloat16`` can include ``float16`` and ``bfloat16`` in the ``real floating`` data type kind. Similarly, implementations supporting ``int128`` can include ``int128`` in the ``signed integer`` data type kind. + + In short, conforming implementations may extend data type kinds; however, data type kinds must remain consistent (e.g., only integer dtypes may belong to integer data type kinds and only floating-point dtypes may belong to floating-point data type kinds), and extensions must be clearly documented as such in library documentation. + + Returns + ------- + out: bool + boolean indicating whether a provided dtype is of a specified data type kind. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def result_type( + *arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] +) -> dtype: + """ + Returns the dtype that results from applying type promotion rules (see :ref:`type-promotion`) to the arguments. + + Parameters + ---------- + arrays_and_dtypes: Union[array, int, float, complex, bool, dtype] + an arbitrary number of input arrays, scalars, and/or dtypes. + + Returns + ------- + out: dtype + the dtype resulting from an operation involving the input arrays, scalars, and/or dtypes. + + Notes + ----- + + - At least one argument must be an array or a dtype. + - If provided array and/or dtype arguments having mixed data type kinds (e.g., integer and floating-point), the returned dtype is unspecified and thus implementation-dependent. + - If at least one argument is an array, the function must determine the resulting dtype according to the type promotion graph of the array device which is shared among all array arguments. As not all devices can support all data types, full support for type promotion rules (see :ref:`type-promotion`) may not be possible. Accordingly, the returned dtype may differ from that determined from the complete type promotion graph defined in this specification (see :ref:`type-promotion`). + - If two or more arguments are arrays belonging to different devices, behavior is unspecified and thus implementation-dependent. Conforming implementations may choose to ignore device attributes, raise an exception, or some other behavior. + + .. versionchanged:: 2024.12 + Added scalar argument support. + + .. versionchanged:: 2024.12 + Required that the application of type promotion rules must account for device context. + """ diff --git a/src/array_api_stubs/_2024_12/data_types.py b/src/array_api_stubs/_2024_12/data_types.py new file mode 100644 index 000000000..d15f4a9f7 --- /dev/null +++ b/src/array_api_stubs/_2024_12/data_types.py @@ -0,0 +1,22 @@ +__all__ = ["__eq__"] + + +from ._types import dtype + + +def __eq__(self: dtype, other: dtype, /) -> bool: + """ + Computes the truth value of ``self == other`` in order to test for data type object equality. + + Parameters + ---------- + self: dtype + data type instance. May be any supported data type. + other: dtype + other data type instance. May be any supported data type. + + Returns + ------- + out: bool + a boolean indicating whether the data type objects are equal. + """ diff --git a/src/array_api_stubs/_2024_12/elementwise_functions.py b/src/array_api_stubs/_2024_12/elementwise_functions.py new file mode 100644 index 000000000..2f0cfc8c3 --- /dev/null +++ b/src/array_api_stubs/_2024_12/elementwise_functions.py @@ -0,0 +1,3060 @@ +__all__ = [ + "abs", + "acos", + "acosh", + "add", + "asin", + "asinh", + "atan", + "atan2", + "atanh", + "bitwise_and", + "bitwise_left_shift", + "bitwise_invert", + "bitwise_or", + "bitwise_right_shift", + "bitwise_xor", + "ceil", + "clip", + "conj", + "copysign", + "cos", + "cosh", + "divide", + "equal", + "exp", + "expm1", + "floor", + "floor_divide", + "greater", + "greater_equal", + "hypot", + "imag", + "isfinite", + "isinf", + "isnan", + "less", + "less_equal", + "log", + "log1p", + "log2", + "log10", + "logaddexp", + "logical_and", + "logical_not", + "logical_or", + "logical_xor", + "maximum", + "minimum", + "multiply", + "negative", + "nextafter", + "not_equal", + "positive", + "pow", + "real", + "reciprocal", + "remainder", + "round", + "sign", + "signbit", + "sin", + "sinh", + "square", + "sqrt", + "subtract", + "tan", + "tanh", + "trunc", +] + + +from ._types import Optional, Union, array + + +def abs(x: array, /) -> array: + r""" + Calculates the absolute value for each element ``x_i`` of the input array ``x``. + + For real-valued input arrays, the element-wise result has the same magnitude as the respective element in ``x`` but has positive sign. + + .. note:: + For signed integer data types, the absolute value of the minimum representable integer is implementation-dependent. + + .. note:: + For complex floating-point operands, the complex absolute value is known as the norm, modulus, or magnitude and, for a complex number :math:`z = a + bj` is computed as + + .. math:: + \operatorname{abs}(z) = \sqrt{a^2 + b^2} + + .. note:: + For complex floating-point operands, conforming implementations should take care to avoid undue overflow or underflow during intermediate stages of computation. + + .. + TODO: once ``hypot`` is added to the specification, remove the special cases for complex floating-point operands and the note concerning guarding against undue overflow/underflow, and state that special cases must be handled as if implemented as ``hypot(real(x), imag(x))``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the absolute value of each element in ``x``. If ``x`` has a real-valued data type, the returned array must have the same data type as ``x``. If ``x`` has a complex floating-point data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``-0``, the result is ``+0``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``+infinity``. + - If ``a`` is any value (including ``NaN``) and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``+infinity``. + - If ``a`` is either ``+0`` or ``-0``, the result is equal to ``abs(b)``. + - If ``b`` is either ``+0`` or ``-0``, the result is equal to ``abs(a)``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acos}(z) = \frac{1}{2}\pi + j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{acos}(z) = \pi - \operatorname{acos}(-z) + + .. note:: + For complex floating-point operands, ``acos(conj(x))`` must equal ``conj(acos(x))``. + + .. note:: + The inverse cosine (or arc cosine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse cosine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[0, \pi]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``π/2 - 0j``. + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``NaN``, the result is ``π/2 + NaN j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``π/2 - infinity j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``π - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 - infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``3π/4 - infinity j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``π/4 - infinity j``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN ± infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``NaN - infinity j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def acosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic cosine of a complex number :math:`z` is + + .. math:: + \operatorname{acosh}(z) = \ln(z + \sqrt{z+1}\sqrt{z-1}) + + For any :math:`z`, + + .. math:: + \operatorname{acosh}(z) = \frac{\sqrt{z-1}}{\sqrt{1-z}}\operatorname{acos}(z) + + or simply + + .. math:: + \operatorname{acosh}(z) = j\ \operatorname{acos}(z) + + in the upper half of the complex plane. + + .. note:: + For complex floating-point operands, ``acosh(conj(x))`` must equal ``conj(acosh(x))``. + + .. note:: + The inverse hyperbolic cosine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segment :math:`(-\infty, 1)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic cosine in the interval :math:`[0, \infty)` along the real axis and in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``1``, the result is ``NaN``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + πj/2``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN ± πj/2`` (sign of imaginary component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def add( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + """ + Calculates the sum for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise sums. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is ``-infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x1_i`` is a finite number and ``x2_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is a nonzero finite number, the result is ``x2_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+0`` or ``-0``, the result is ``x1_i``. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is ``-x1_i``, the result is ``+0``. + - In the remaining cases, when neither ``infinity``, ``+0``, ``-0``, nor a ``NaN`` is involved, and the operands have the same mathematical sign or have different magnitudes, the sum must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported round mode. If the magnitude is too large to represent, the operation overflows and the result is an `infinity` of appropriate mathematical sign. + + .. note:: + Floating-point addition is a commutative operation, but not always associative. + + For complex floating-point operands, addition is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+------------+------------+----------------+ + | | c | dj | c + dj | + +============+============+============+================+ + | **a** | a + c | a + dj | (a+c) + dj | + +------------+------------+------------+----------------+ + | **bj** | c + bj | (b+d)j | c + (b+d)j | + +------------+------------+------------+----------------+ + | **a + bj** | (a+c) + bj | a + (b+d)j | (a+c) + (b+d)j | + +------------+------------+------------+----------------+ + + For complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. For example, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a`` is ``-0`` and ``c`` is ``-0``, the real component of the result is ``-0``. + - Similarly, if ``b`` is ``+0`` and ``d`` is ``-0``, the imaginary component of the result is ``+0``. + + Hence, if ``z1 = a + bj = -0 + 0j`` and ``z2 = c + dj = -0 - 0j``, the result of ``z1 + z2`` is ``-0 + 0j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def asin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the arc sine of a complex number :math:`z` is + + .. math:: + \operatorname{asin}(z) = -j\ \ln(zj + \sqrt{1-z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asin}(z) = \operatorname{acos}(-z) - \frac{\pi}{2} + + .. note:: + For complex floating-point operands, ``asin(conj(x))`` must equal ``conj(asin(x))``. + + .. note:: + The inverse sine (or arc sine) is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, -1)` and :math:`(1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse sine in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * asinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def asinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element ``x_i`` in the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic sine of a complex number :math:`z` is + + .. math:: + \operatorname{asinh}(z) = \ln(z + \sqrt{1+z^2}) + + For any :math:`z`, + + .. math:: + \operatorname{asinh}(z) = \frac{\operatorname{asin}(zj)}{j} + + .. note:: + For complex floating-point operands, ``asinh(conj(x))`` must equal ``conj(asinh(x))`` and ``asinh(-z)`` must equal ``-asinh(z)``. + + .. note:: + The inverse hyperbolic sine is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic sine in the range of a strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element ``x_i`` of the input array ``x``. + + Each element-wise result is expressed in radians. + + .. note:: + The principal value of the inverse tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atan}(z) = -\frac{\ln(1 - zj) - \ln(1 + zj)}{2}j + + .. note:: + For complex floating-point operands, ``atan(conj(x))`` must equal ``conj(atan(x))``. + + .. note:: + The inverse tangent (or arc tangent) is a multi-valued function and requires a branch on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty j, -j)` and :math:`(+j, \infty j)` of the imaginary axis. + + Accordingly, for complex arguments, the function returns the inverse tangent in the range of a strip unbounded along the imaginary axis and in the interval :math:`[-\pi/2, +\pi/2]` along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π/2``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * atanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def atan2(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Calculates an implementation-dependent approximation of the inverse tangent of the quotient ``x1/x2``, having domain ``[-infinity, +infinity] x [-infinity, +infinity]`` (where the ``x`` notation denotes the set of ordered pairs of elements ``(x1_i, x2_i)``) and codomain ``[-π, +π]``, for each pair of elements ``(x1_i, x2_i)`` of the input arrays ``x1`` and ``x2``, respectively. Each element-wise result is expressed in radians. + + The mathematical signs of ``x1_i`` and ``x2_i`` determine the quadrant of each element-wise result. The quadrant (i.e., branch) is chosen such that each element-wise result is the signed angle in radians between the ray ending at the origin and passing through the point ``(1,0)`` and the ray ending at the origin and passing through the point ``(x2_i, x1_i)``. + + .. note:: + Note the role reversal: the "y-coordinate" is the first function parameter; the "x-coordinate" is the second function parameter. The parameter order is intentional and traditional for the two-argument inverse tangent function where the y-coordinate argument is first and the x-coordinate argument is second. + + By IEEE 754 convention, the inverse tangent of the quotient ``x1/x2`` is defined for ``x2_i`` equal to positive or negative zero and for either or both of ``x1_i`` and ``x2_i`` equal to positive or negative ``infinity``. + + Parameters + ---------- + x1: Union[array, int, float] + input array corresponding to the y-coordinates. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + input array corresponding to the x-coordinates. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the inverse tangent of the quotient ``x1/x2``. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is greater than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+π``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-π``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``+π/2``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a finite number, the result is an implementation-dependent approximation to ``-π/2``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``+π/4``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``+3π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is an implementation-dependent approximation to ``-π/4``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is an implementation-dependent approximation to ``-3π/4``. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def atanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + .. note:: + The principal value of the inverse hyperbolic tangent of a complex number :math:`z` is + + .. math:: + \operatorname{atanh}(z) = \frac{\ln(1+z)-\ln(z-1)}{2} + + For any :math:`z`, + + .. math:: + \operatorname{atanh}(z) = \frac{\operatorname{atan}(zj)}{j} + + .. note:: + For complex floating-point operands, ``atanh(conj(x))`` must equal ``conj(atanh(x))`` and ``atanh(-x)`` must equal ``-atanh(x)``. + + .. note:: + The inverse hyperbolic tangent is a multi-valued function and requires a branch cut on the complex plane. By convention, a branch cut is placed at the line segments :math:`(-\infty, 1]` and :math:`[1, \infty)` of the real axis. + + Accordingly, for complex arguments, the function returns the inverse hyperbolic tangent in the range of a half-strip unbounded along the real axis and in the interval :math:`[-\pi j/2, +\pi j/2]` along the imaginary axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array whose elements each represent the area of a hyperbolic sector. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the inverse hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is greater than ``1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``+1``, the result is ``+infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``1`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+0 + πj/2``. + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``±0 + πj/2`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def bitwise_and(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: + """ + Computes the bitwise AND of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, bool] + first input array. Should have an integer or boolean data type. + x2: Union[array, int, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_left_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the left by appending ``x2_i`` (i.e., the respective element in the input array ``x2``) zeros to the right of ``x1_i``. + + Parameters + ---------- + x1: Union[array, int] + first input array. Should have an integer data type. + x2: Union[array, int] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_invert(x: array, /) -> array: + """ + Inverts (flips) each bit for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + """ + + +def bitwise_or(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: + """ + Computes the bitwise OR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, bool] + first input array. Should have an integer or boolean data type. + x2: Union[array, int, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_right_shift(x1: Union[array, int], x2: Union[array, int], /) -> array: + """ + Shifts the bits of each element ``x1_i`` of the input array ``x1`` to the right according to the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This operation must be an arithmetic shift (i.e., sign-propagating) and thus equivalent to floor division by a power of two. + + Parameters + ---------- + x1: Union[array, int] + first input array. Should have an integer data type. + x2: Union[array, int] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer data type. Each element must be greater than or equal to ``0``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def bitwise_xor(x1: Union[array, int, bool], x2: Union[array, int, bool], /) -> array: + """ + Computes the bitwise XOR of the underlying binary representation of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, bool] + first input array. Should have an integer or boolean data type. + x2: Union[array, int, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have an integer or boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def ceil(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the smallest (i.e., closest to ``-infinity``) integer-valued number that is not less than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def clip( + x: array, + /, + min: Optional[Union[int, float, array]] = None, + max: Optional[Union[int, float, array]] = None, +) -> array: + r""" + Clamps each element ``x_i`` of the input array ``x`` to the range ``[min, max]``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + min: Optional[Union[int, float, array]] + lower-bound of the range to which to clamp. If ``None``, no lower bound must be applied. Must be compatible with ``x`` and ``max`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. + max: Optional[Union[int, float, array]] + upper-bound of the range to which to clamp. If ``None``, no upper bound must be applied. Must be compatible with ``x`` and ``min`` (see :ref:`broadcasting`). Should have the same data type as ``x``. Default: ``None``. + + Returns + ------- + out: array + an array containing element-wise results. The returned array should have the same data type as ``x``. + + Notes + ----- + + - This function is conceptually equivalent to ``maximum(minimum(x, max), min)`` when ``x``, ``min``, and ``max`` have the same data type. + - If both ``min`` and ``max`` are ``None``, the elements of the returned array must equal the respective elements in ``x``. + - If a broadcasted element in ``min`` is greater than a corresponding broadcasted element in ``max``, behavior is unspecified and thus implementation-dependent. + - For scalar ``min`` and/or ``max``, the scalar values should follow type promotion rules for operations involving arrays and scalar operands (see :ref:`type-promotion`). Hence, if ``x`` and either ``min`` or ``max`` have different data type kinds (e.g., integer versus floating-point), behavior is unspecified and thus implementation-dependent. + - If ``x`` has an integral data type and a broadcasted element in ``min`` or ``max`` is outside the bounds of the data type of ``x``, behavior is unspecified and thus implementation-dependent. + - If either ``min`` or ``max`` is an array having a different data type than ``x``, behavior is unspecified and thus implementation-dependent. + + **Special cases** + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``min_i`` is ``NaN``, the result is ``NaN``. + - If ``max_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added special case behavior when one of the operands is ``NaN``. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when ``x``, ``min``, and ``max`` resolve to arrays having the same data type. + + .. versionchanged:: 2024.12 + Clarified that behavior is only defined when elements of ``min`` and ``max`` are inside the bounds of the input array data type. + """ + + +def conj(x: array, /) -> array: + """ + Returns the complex conjugate for each element ``x_i`` of the input array ``x``. + + For complex numbers of the form + + .. math:: + a + bj + + the complex conjugate is defined as + + .. math:: + a - bj + + Hence, the returned complex conjugates must be computed by negating the imaginary component of each element ``x_i``. + + Parameters + ---------- + x: array + input array. Must have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x``. + + Notes + ----- + + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. + """ + + +def copysign(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Composes a floating-point value with the magnitude of ``x1_i`` and the sign of ``x2_i`` for each element of the input array ``x1``. + + Parameters + ---------- + x1: Union[array, int, float] + input array containing magnitudes. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + input array whose sign bits are applied to the magnitudes of ``x1``. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, let ``|x|`` be the absolute value, and if ``x1_i`` is not ``NaN``, + + - If ``x2_i`` is less than ``0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``-0``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``+0``, the result is ``|x1_i|``. + - If ``x2_i`` is greater than ``0``, the result is ``|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``-|x1_i|``. + - If ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``|x1_i|``. + + - If ``x1_i`` is ``NaN`` and ``x2_i`` is less than ``0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``-0``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``+0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is greater than ``0``, the result is ``NaN`` with a sign bit of ``0``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``1``, the result is ``NaN`` with a sign bit of ``1``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is ``NaN`` and the sign bit of ``x2_i`` is ``0``, the result is ``NaN`` with a sign bit of ``0``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def cos(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the cosine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The cosine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of cosine is + + .. math:: + \begin{align} \operatorname{cos}(x) &= \sum_{n=0}^\infty \frac{(-1)^n}{(2n)!} x^{2n} \\ &= \frac{e^{jx} + e^{-jx}}{2} \\ &= \operatorname{cosh}(jx) \end{align} + + where :math:`\operatorname{cosh}` is the hyperbolic cosine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``NaN``. + - If ``x_i`` is ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``cosh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cosh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic cosine for each element ``x_i`` in the input array ``x``. + + The mathematical definition of the hyperbolic cosine is + + .. math:: + \operatorname{cosh}(x) = \frac{e^x + e^{-x}}{2} + + .. note:: + The hyperbolic cosine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic cosine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``cosh(x)`` must equal ``cosh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``cosh(conj(x))`` must equal ``conj(cosh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is either ``+0`` or ``-0``, the result is ``NaN + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def divide( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + r""" + Calculates the division of each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + dividend input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + - If one or both of the input arrays have integer data types, the result is implementation-dependent, as type promotion between data type "kinds" (e.g., integer versus floating-point) is unspecified. + + Specification-compliant libraries may choose to raise an error or return an array containing the element-wise results. If an array is returned, the array must have a real-valued floating-point data type. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, division is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a / c | -(a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b/c)j | b/d | special rules | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a/c) + (b/c)j | b/d - (a/d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), division of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number division + + .. math:: + \frac{a + bj}{c + dj} = \frac{(ac + bd) + (bc - ad)j}{c^2 + d^2} + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex division. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex division according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: + r""" + Computes the truth value of ``x1_i == x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``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. Must be compatible with ``x1`` (see :ref:`broadcasting`). May have any data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``False``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` equals ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``False``. + - In the remaining cases, the result is the logical AND of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a == c AND b == d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def exp(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to the exponential function for each element ``x_i`` of the input array ``x`` (``e`` raised to the power of ``x_i``, where ``e`` is the base of the natural logarithm). + + .. note:: + For complex floating-point operands, ``exp(conj(x))`` must equal ``conj(exp(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated exponential function result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``1``. + - If ``x_i`` is ``-0``, the result is ``1``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``+0``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``1 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``0 + 0j`` (signs of real and imaginary components are unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def expm1(x: array, /) -> array: + """ + Calculates an implementation-dependent approximation to ``exp(x)-1`` for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``exp(x)-1.0`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``exp(x)-1.0``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``expm1(conj(x))`` must equal ``conj(expm1(x))``. + + .. note:: + The exponential function is an entire function in the complex plane and has no branch cuts. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``0 + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is a finite number, the result is ``+0 * cis(b) - 1.0``. + - If ``a`` is ``+infinity`` and ``b`` is a nonzero finite number, the result is ``+infinity * cis(b) - 1.0``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``-1 + 0j`` (sign of imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is not equal to ``0``, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def floor(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the greatest (i.e., closest to ``+infinity``) integer-valued number that is not greater than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ + + +def floor_divide( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: + r""" + Rounds the result of dividing each element ``x1_i`` of the input array ``x1`` by the respective element ``x2_i`` of the input array ``x2`` to the greatest (i.e., closest to `+infinity`) integer-value number that is not greater than the division result. + + Parameters + ---------- + x1: Union[array, int, float] + dividend input array. Should have a real-valued data type. + x2: Union[array, int, float] + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + **Special cases** + + .. note:: + Floor division was introduced in Python via `PEP 238 `_ with the goal to disambiguate "true division" (i.e., computing an approximation to the mathematical operation of division) from "floor division" (i.e., rounding the result of division toward negative infinity). The former was computed when one of the operands was a ``float``, while the latter was computed when both operands were ``int``\s. Overloading the ``/`` operator to support both behaviors led to subtle numerical bugs when integers are possible, but not expected. + + To resolve this ambiguity, ``/`` was designated for true division, and ``//`` was designated for floor division. Semantically, floor division was `defined `_ as equivalent to ``a // b == floor(a/b)``; however, special floating-point cases were left ill-defined. + + Accordingly, floor division is not implemented consistently across array libraries for some of the special cases documented below. Namely, when one of the operands is ``infinity``, libraries may diverge with some choosing to strictly follow ``floor(a/b)`` and others choosing to pair ``//`` with ``%`` according to the relation ``b = a % b + b * (a // b)``. The special cases leading to divergent behavior are documented below. + + This specification prefers floor division to match ``floor(divide(x1, x2))`` in order to avoid surprising and unexpected results; however, array libraries may choose to more strictly follow Python behavior. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``-0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``+infinity``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``-infinity``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``-infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``+infinity``. (**note**: libraries may return ``NaN`` to match Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``-0``. (**note**: libraries may return ``-1.0`` to match Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign and are both nonzero finite numbers, the result has a positive mathematical sign. + - If ``x1_i`` and ``x2_i`` have different mathematical signs and are both nonzero finite numbers, the result has a negative mathematical sign. + - In the remaining cases, where neither ``-infinity``, ``+0``, ``-0``, nor ``NaN`` is involved, the quotient must be computed and rounded to the greatest (i.e., closest to `+infinity`) representable integer-value number that is not greater than the division result. If the magnitude is too large to represent, the operation overflows and the result is an ``infinity`` of appropriate mathematical sign. If the magnitude is too small to represent, the operation underflows and the result is a zero of appropriate mathematical sign. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def greater(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Computes the truth value of ``x1_i > x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def greater_equal( + x1: Union[array, int, float], x2: Union[array, int, float], / +) -> array: + """ + Computes the truth value of ``x1_i >= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def hypot(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Computes the square root of the sum of squares for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + The value computed by this function may be interpreted as the length of the hypotenuse of a right-angled triangle with sides of length ``x1_i`` and ``x2_i``, the distance of a point ``(x1_i, x2_i)`` from the origin ``(0, 0)``, or the magnitude of a complex number ``x1_i + x2_i * 1j``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The purpose of this function is to avoid underflow and overflow during intermediate stages of computation. Accordingly, conforming implementations should not use naive implementations. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``+infinity`` or ``-infinity`` and ``x2_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x2_i`` is ``+infinity`` or ``-infinity`` and ``x1_i`` is any value, including ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x2_i)``. + - If ``x2_i`` is either ``+0`` or ``-0``, the result is equivalent to ``abs(x1_i)``. + - If ``x1_i`` is a finite number or ``NaN`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is a finite number or ``NaN`` and ``x1_i`` is ``NaN``, the result is ``NaN``. + - Underflow may only occur when both arguments are subnormal and the correct result is also subnormal. + + For real-valued floating-point operands, ``hypot(x1, x2)`` must equal ``hypot(x2, x1)``, ``hypot(x1, -x2)``, ``hypot(-x1, x2)``, and ``hypot(-x1, -x2)``. + + .. note:: + IEEE 754-2019 requires support for subnormal (a.k.a., denormal) numbers, which are useful for supporting gradual underflow. However, hardware support for subnormal numbers is not universal, and many platforms (e.g., accelerators) and compilers support toggling denormals-are-zero (DAZ) and/or flush-to-zero (FTZ) behavior to increase performance and to guard against timing attacks. + + Accordingly, conforming implementations may vary in their support for subnormal numbers. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def imag(x: array, /) -> array: + """ + Returns the imaginary component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def isfinite(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if finite. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``x_i`` is ``NaN``, the result is ``False``. + - If ``x_i`` is a finite number, the result is ``True``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``False``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value, the result is ``False``. + - If ``a`` is any value and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``False``. + - If ``a`` is a finite number and ``b`` is a finite number, the result is ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isinf(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine if equal to positive or negative infinity. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is any value (including ``NaN``), the result is ``True``. + - If ``a`` is either a finite number or ``NaN`` and ``b`` is either ``+infinity`` or ``-infinity``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def isnan(x: array, /) -> array: + """ + Tests each element ``x_i`` of the input array ``x`` to determine whether the element is ``NaN``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing test results. The returned array should have a data type of ``bool``. + + Notes + ----- + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` or ``b`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def less(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Computes the truth value of ``x1_i < x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def less_equal(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Computes the truth value of ``x1_i <= x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def log(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the natural (base ``e``) logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + The natural logarithm of a complex number :math:`z` with polar coordinates :math:`(r,\theta)` equals :math:`\ln r + (\theta + 2n\pi)j` with principal value :math:`\ln r + \theta j`. + + .. note:: + For complex floating-point operands, ``log(conj(x))`` must equal ``conj(log(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated natural logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-0`` and ``b`` is ``+0``, the result is ``-infinity + πj``. + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log1p(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to ``log(1+x)``, where ``log`` refers to the natural (base ``e``) logarithm, for each element ``x_i`` of the input array ``x``. + + .. note:: + The purpose of this function is to calculate ``log(1+x)`` more accurately when `x` is close to zero. Accordingly, conforming implementations should avoid implementing this function as simply ``log(1+x)``. See FDLIBM, or some other IEEE 754-2019 compliant mathematical library, for a potential reference implementation. + + .. note:: + For complex floating-point operands, ``log1p(conj(x))`` must equal ``conj(log1p(x))``. + + .. note:: + By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the natural logarithm in the range of a strip in the interval :math:`[-\pi j, +\pi j]` along the imaginary axis and mathematically unbounded along the real axis. + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``-1``, the result is ``NaN``. + - If ``x_i`` is ``-1``, the result is ``-infinity``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is ``-1`` and ``b`` is ``+0``, the result is ``-infinity + 0j``. + - If ``a`` is a finite number and ``b`` is ``+infinity``, the result is ``+infinity + πj/2``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + πj``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+infinity + 0j``. + - If ``a`` is ``-infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + 3πj/4``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``+infinity + πj/4``. + - If ``a`` is either ``+infinity`` or ``-infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is a finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``+infinity``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log2(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``2`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log2(conj(x))`` must equal ``conj(log2(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``2`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{2} x = \frac{\log_{e} x}{\log_{e} 2} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def log10(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the base ``10`` logarithm for each element ``x_i`` of the input array ``x``. + + .. note:: + For complex floating-point operands, ``log10(conj(x))`` must equal ``conj(log10(x))``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated base ``10`` logarithm for each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is either ``+0`` or ``-0``, the result is ``-infinity``. + - If ``x_i`` is ``1``, the result is ``+0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented using the standard change of base formula + + .. math:: + \log_{10} x = \frac{\log_{e} x}{\log_{e} 10} + + where :math:`\log_{e}` is the natural logarithm, as implemented by :func:`~array_api.log`. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def logaddexp(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Calculates the logarithm of the sum of exponentiations ``log(exp(x1) + exp(x2))`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is not ``NaN``, the result is ``+infinity``. + - If ``x1_i`` is not ``NaN`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def logical_and(x1: Union[array, bool], x2: Union[array, bool], /) -> array: + """ + Computes the logical AND for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: Union[array, bool] + first input array. Should have a boolean data type. + x2: Union[array, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of `bool`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def logical_not(x: array, /) -> array: + """ + Computes the logical NOT for each element ``x_i`` of the input array ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x: array + input array. Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + """ + + +def logical_or(x1: Union[array, bool], x2: Union[array, bool], /) -> array: + """ + Computes the logical OR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: Union[array, bool] + first input array. Should have a boolean data type. + x2: Union[array, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def logical_xor(x1: Union[array, bool], x2: Union[array, bool], /) -> array: + """ + Computes the logical XOR for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + While this specification recommends that this function only accept input arrays having a boolean data type, specification-compliant array libraries may choose to accept input arrays having real-valued data types. If non-boolean data types are supported, zeros must be considered the equivalent of ``False``, while non-zeros must be considered the equivalent of ``True``. + + Parameters + ---------- + x1: Union[array, bool] + first input array. Should have a boolean data type. + x2: Union[array, bool] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a boolean data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def maximum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Computes the maximum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise maximum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def minimum(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + r""" + Computes the minimum value for each element ``x1_i`` of the input array ``x1`` relative to the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise minimum values. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + - For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def multiply( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + r""" + Calculates the product for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + Floating-point multiplication is not always associative due to finite precision. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise products. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` and ``x2_i`` have the same mathematical sign, the result has a positive mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` and ``x2_i`` have different mathematical signs, the result has a negative mathematical sign, unless the result is ``NaN``. If the result is ``NaN``, the "sign" of ``NaN`` is implementation-defined. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is a nonzero finite number, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - If ``x1_i`` is a nonzero finite number and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is a signed infinity with the mathematical sign determined by the rule already stated above. + - In the remaining cases, where neither ``infinity`` nor ``NaN`` is involved, the product must be computed and rounded to the nearest representable value according to IEEE 754-2019 and a supported rounding mode. If the magnitude is too large to represent, the result is an `infinity` of appropriate mathematical sign. If the magnitude is too small to represent, the result is a zero of appropriate mathematical sign. + + For complex floating-point operands, multiplication is defined according to the following table. For real components ``a`` and ``c`` and imaginary components ``b`` and ``d``, + + +------------+----------------+-----------------+--------------------------+ + | | c | dj | c + dj | + +============+================+=================+==========================+ + | **a** | a * c | (a*d)j | (a*c) + (a*d)j | + +------------+----------------+-----------------+--------------------------+ + | **bj** | (b*c)j | -(b*d) | -(b*d) + (b*c)j | + +------------+----------------+-----------------+--------------------------+ + | **a + bj** | (a*c) + (b*c)j | -(b*d) + (a*d)j | special rules | + +------------+----------------+-----------------+--------------------------+ + + In general, for complex floating-point operands, real-valued floating-point special cases must independently apply to the real and imaginary component operations involving real numbers as described in the above table. + + When ``a``, ``b``, ``c``, or ``d`` are all finite numbers (i.e., a value other than ``NaN``, ``+infinity``, or ``-infinity``), multiplication of complex floating-point operands should be computed as if calculated according to the textbook formula for complex number multiplication + + .. math:: + (a + bj) \cdot (c + dj) = (ac - bd) + (bc + ad)j + + When at least one of ``a``, ``b``, ``c``, or ``d`` is ``NaN``, ``+infinity``, or ``-infinity``, + + - If ``a``, ``b``, ``c``, and ``d`` are all ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, the result is implementation dependent. + + .. note:: + For complex floating-point operands, the results of special cases may be implementation dependent depending on how an implementation chooses to model complex numbers and complex infinity (e.g., complex plane versus Riemann sphere). For those implementations following C99 and its one-infinity model, when at least one component is infinite, even if the other component is ``NaN``, the complex value is infinite, and the usual arithmetic rules do not apply to complex-complex multiplication. In the interest of performance, other implementations may want to avoid the complex branching logic necessary to implement the one-infinity model and choose to implement all complex-complex multiplication according to the textbook formula. Accordingly, special case behavior is unlikely to be consistent across implementations. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def negative(x: array, /) -> array: + """ + Computes the numerical negative of each element ``x_i`` (i.e., ``y_i = -x_i``) of the input array ``x``. + + .. note:: + For signed integer data types, the numerical negative of the minimum representable integer is implementation-dependent. + + .. note:: + If ``x`` has a complex floating-point data type, both the real and imaginary components for each ``x_i`` must be negated (a result which follows from the rules of complex number multiplication). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def nextafter(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Returns the next representable floating-point value for each element ``x1_i`` of the input array ``x1`` in the direction of the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float] + first input array. Should have a real-valued floating-point data type. + x2: Union[array, int, float] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have the same data type as ``x1``. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have the same data type as ``x1``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special cases** + + For real-valued floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is ``+0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is ``-0``, the result is ``-0``. + + .. versionadded:: 2024.12 + """ + + +def not_equal( + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: + """ + Computes the truth value of ``x1_i != x2_i`` for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``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. Must be compatible with ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type of ``bool``. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + **Special Cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is ``NaN`` or ``x2_i`` is ``NaN``, the result is ``True``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is ``-infinity``, the result is ``True``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is ``+infinity``, the result is ``True``. + - If ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x1_i`` does not equal ``x2_i``, the result is ``True``. + - In the remaining cases, the result is ``False``. + + For complex floating-point operands, let ``a = real(x1_i)``, ``b = imag(x1_i)``, ``c = real(x2_i)``, ``d = imag(x2_i)``, and + + - If ``a``, ``b``, ``c``, or ``d`` is ``NaN``, the result is ``True``. + - In the remaining cases, the result is the logical OR of the equality comparison between the real values ``a`` and ``c`` (real components) and between the real values ``b`` and ``d`` (imaginary components), as described above for real-valued floating-point operands (i.e., ``a != c OR b != d``). + + .. note:: + For discussion of complex number equality, see :ref:`complex-numbers`. + + .. note:: + Comparison of arrays without a corresponding promotable data type (see :ref:`type-promotion`) is undefined and thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Cross-kind comparisons are explicitly left unspecified. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def positive(x: array, /) -> array: + """ + Computes the numerical positive of each element ``x_i`` (i.e., ``y_i = +x_i``) of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pow( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + r""" + Calculates an implementation-dependent approximation of exponentiation by raising each element ``x1_i`` (the base) of the input array ``x1`` to the power of ``x2_i`` (the exponent), where ``x2_i`` is the corresponding element of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array whose elements correspond to the exponentiation base. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array whose elements correspond to the exponentiation exponent. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + + - If both ``x1`` and ``x2`` have integer data types, the result of ``pow`` when ``x2_i`` is negative (i.e., less than zero) is unspecified and thus implementation-dependent. + + - If ``x1`` has an integer data type and ``x2`` has a floating-point data type, behavior is implementation-dependent (type promotion between data type "kinds" (integer versus floating-point) is unspecified). + + - By convention, the branch cut of the natural logarithm is the negative real axis :math:`(-\infty, 0)`. + + The natural logarithm is a continuous function from above the branch cut, taking into account the sign of the imaginary component. As special cases involving complex floating-point operands should be handled according to ``exp(x2*log(x1))``, exponentiation has the same branch cut for ``x1`` as the natural logarithm (see :func:`~array_api.log`). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + **Special cases** + + For real-valued floating-point operands, + + - If ``x1_i`` is not equal to ``1`` and ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x2_i`` is ``+0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x2_i`` is ``-0``, the result is ``1``, even if ``x1_i`` is ``NaN``. + - If ``x1_i`` is ``NaN`` and ``x2_i`` is not equal to ``0``, the result is ``NaN``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+infinity``. + - If ``abs(x1_i)`` is greater than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``+infinity``, the result is ``1``. + - If ``abs(x1_i)`` is ``1`` and ``x2_i`` is ``-infinity``, the result is ``1``. + - If ``x1_i`` is ``1`` and ``x2_i`` is not ``NaN``, the result is ``1``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``+infinity``, the result is ``+0``. + - If ``abs(x1_i)`` is less than ``1`` and ``x2_i`` is ``-infinity``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is greater than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is less than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-infinity``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``+infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is an odd integer value, the result is ``-0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is greater than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+0``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is an odd integer value, the result is ``-infinity``. + - If ``x1_i`` is ``-0``, ``x2_i`` is less than ``0``, and ``x2_i`` is not an odd integer value, the result is ``+infinity``. + - If ``x1_i`` is less than ``0``, ``x1_i`` is a finite number, ``x2_i`` is a finite number, and ``x2_i`` is not an integer value, the result is ``NaN``. + + For complex floating-point operands, special cases should be handled as if the operation is implemented as ``exp(x2*log(x1))``. + + .. note:: + Conforming implementations are allowed to treat special cases involving complex floating-point operands more carefully than as described in this specification. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def real(x: array, /) -> array: + """ + Returns the real component of a complex number for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Must have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type with the same floating-point precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have the floating-point data type ``float32``). + + Notes + ----- + + - Whether the returned array and the input array share the same underlying memory is unspecified and thus implementation-defined. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2024.12 + Added support for real-valued arrays. + """ + + +def reciprocal(x: array, /) -> array: + """ + Returns the reciprocal for each element ``x_i`` of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the element-wise results. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``1.0 / x`` (see :func:`~array_api.divide`). + + .. versionadded:: 2024.12 + """ + + +def remainder(x1: Union[array, int, float], x2: Union[array, int, float], /) -> array: + """ + Returns the remainder of division for each element ``x1_i`` of the input array ``x1`` and the respective element ``x2_i`` of the input array ``x2``. + + .. note:: + This function is equivalent to the Python modulus operator ``x1_i % x2_i``. + + Parameters + ---------- + x1: Union[array, int, float] + dividend input array. Should have a real-valued data type. + x2: Union[array, int, float] + divisor input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the element-wise results. Each element-wise result must have the same sign as the respective element ``x2_i``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - For input arrays which promote to an integer data type, the result of division by zero is unspecified and thus implementation-defined. + + **Special cases** + + .. note:: + In general, similar to Python's ``%`` operator, this function is **not** recommended for floating-point operands as semantics do not follow IEEE 754. That this function is specified to accept floating-point operands is primarily for reasons of backward compatibility. + + For floating-point operands, + + - If either ``x1_i`` or ``x2_i`` is ``NaN``, the result is ``NaN``. + - If ``x1_i`` is either ``+infinity`` or ``-infinity`` and ``x2_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + - If ``x1_i`` is either ``+0`` or ``-0`` and ``x2_i`` is either ``+0`` or ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is greater than ``0``, the result is ``+0``. + - If ``x1_i`` is ``+0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is ``-0`` and ``x2_i`` is less than ``0``, the result is ``-0``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is greater than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``+0``, the result is ``NaN``. + - If ``x1_i`` is less than ``0`` and ``x2_i`` is ``-0``, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``+infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is ``-infinity`` and ``x2_i`` is a negative (i.e., less than ``0``) finite number, the result is ``NaN``. + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a positive (i.e., greater than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x2_i``. (**note**: this result matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``+infinity``, the result is ``x2_i``. (**note**: this results matches Python behavior.) + - If ``x1_i`` is a negative (i.e., less than ``0``) finite number and ``x2_i`` is ``-infinity``, the result is ``x1_i``. (**note**: this result matches Python behavior.) + - In the remaining cases, the result must match that of the Python ``%`` operator. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def round(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number. + + .. note:: + For complex floating-point operands, real and imaginary components must be independently rounded to the nearest integer-valued number. + + Rounded real and imaginary components must be equal to their equivalent rounded real-valued floating-point counterparts (i.e., for complex-valued ``x``, ``real(round(x))`` must equal ``round(real(x)))`` and ``imag(round(x))`` must equal ``round(imag(x))``). + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + .. note:: + For complex floating-point operands, the following special cases apply to real and imaginary components independently (e.g., if ``real(x_i)`` is ``NaN``, the rounded real component is ``NaN``). + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If two integers are equally close to ``x_i``, the result is the even integer closest to ``x_i``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sign(x: array, /) -> array: + r""" + Returns an indication of the sign of a number for each element ``x_i`` of the input array ``x``. + + The sign function (also known as the **signum function**) of a number :math:`x_i` is defined as + + .. math:: + \operatorname{sign}(x_i) = \begin{cases} + 0 & \textrm{if } x_i = 0 \\ + \frac{x_i}{|x_i|} & \textrm{otherwise} + \end{cases} + + where :math:`|x_i|` is the absolute value of :math:`x_i`. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + For real-valued operands, + + - If ``x_i`` is less than ``0``, the result is ``-1``. + - If ``x_i`` is either ``-0`` or ``+0``, the result is ``0``. + - If ``x_i`` is greater than ``0``, the result is ``+1``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``-0`` or ``+0`` and ``b`` is either ``-0`` or ``+0``, the result is ``0 + 0j``. + - If ``a`` is ``NaN`` or ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - In the remaining cases, special cases must be handled according to the rules of complex number division (see :func:`~array_api.divide`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def signbit(x: array, /) -> array: + r""" + Determines whether the sign bit is set for each element ``x_i`` of the input array ``x``. + + The sign bit of a real-valued floating-point number ``x_i`` is set whenever ``x_i`` is either ``-0``, less than zero, or a signed ``NaN`` (i.e., a ``NaN`` value whose sign bit is ``1``). + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type of ``bool``. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``+0``, the result is ``False``. + - If ``x_i`` is ``-0``, the result is ``True``. + - If ``x_i`` is ``+infinity``, the result is ``False``. + - If ``x_i`` is ``-infinity``, the result is ``True``. + - If ``x_i`` is a positive (i.e., greater than ``0``) finite number, the result is ``False``. + - If ``x_i`` is a negative (i.e., less than ``0``) finite number, the result is ``True``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``0``, the result is ``False``. + - If ``x_i`` is ``NaN`` and the sign bit of ``x_i`` is ``1``, the result is ``True``. + + .. versionadded:: 2023.12 + """ + + +def sin(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the sine for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + The sine is an entire function on the complex plane and has no branch cuts. + + .. note:: + For complex arguments, the mathematical definition of sine is + + .. math:: + \begin{align} \operatorname{sin}(x) &= \frac{e^{jx} - e^{-jx}}{2j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \\ &= \frac{\operatorname{sinh}(jx)}{j} \cdot \frac{j}{j} \\ &= -j \cdot \operatorname{sinh}(jx) \end{align} + + where :math:`\operatorname{sinh}` is the hyperbolic sine. + + Parameters + ---------- + x: array + input array whose elements are each expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * sinh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sinh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic sine for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic sine is + + .. math:: + \operatorname{sinh}(x) = \frac{e^x - e^{-x}}{2} + + .. note:: + The hyperbolic sine is an entire function in the complex plane and has no branch cuts. The function is periodic, with period :math:`2\pi j`, with respect to the imaginary component. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic sine of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``sinh(x)`` must equal ``-sinh(-x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``sinh(conj(x))`` must equal ``conj(sinh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``0 + NaN j`` (sign of the real component is unspecified). + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is a positive (i.e., greater than ``0``) finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+0``, the result is ``+infinity + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive finite number, the result is ``+infinity * cis(b)``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``infinity + NaN j`` (sign of the real component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + where ``cis(v)`` is ``cos(v) + sin(v)*1j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def square(x: array, /) -> array: + r""" + Squares each element ``x_i`` of the input array ``x``. + + The square of a number ``x_i`` is defined as + + .. math:: + x_i^2 = x_i \cdot x_i + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + + Returns + ------- + out: array + an array containing the evaluated result for each element in ``x``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For floating-point operands, special cases must be handled as if the operation is implemented as ``x * x`` (see :func:`~array_api.multiply`). + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def sqrt(x: array, /) -> array: + r""" + Calculates the principal square root for each element ``x_i`` of the input array ``x``. + + .. note:: + After rounding, each result must be indistinguishable from the infinitely precise result (as required by IEEE 754). + + .. note:: + For complex floating-point operands, ``sqrt(conj(x))`` must equal ``conj(sqrt(x))``. + + .. note:: + By convention, the branch cut of the square root is the negative real axis :math:`(-\infty, 0)`. + + The square root is a continuous function from above the branch cut, taking into account the sign of the imaginary component. + + Accordingly, for complex arguments, the function returns the square root in the range of the right half-plane, including the imaginary axis (i.e., the plane defined by :math:`[0, +\infty)` along the real axis and :math:`(-\infty, +\infty)` along the imaginary axis). + + *Note: branch cuts follow C99 and have provisional status* (see :ref:`branch-cuts`). + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the square root of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is less than ``0``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + - If ``a`` is either ``+0`` or ``-0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is any value (including ``NaN``) and ``b`` is ``+infinity``, the result is ``+infinity + infinity j``. + - If ``a`` is a finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` ``-infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``NaN + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``+0 + infinity j``. + - If ``a`` is ``-infinity`` and ``b`` is ``NaN``, the result is ``NaN + infinity j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``+infinity + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is any value, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def subtract( + x1: Union[array, int, float, complex], x2: Union[array, int, float, complex], / +) -> array: + """ + Calculates the difference for each element ``x1_i`` of the input array ``x1`` with the respective element ``x2_i`` of the input array ``x2``. + + Parameters + ---------- + x1: Union[array, int, float, complex] + first input array. Should have a numeric data type. + x2: Union[array, int, float, complex] + second input array. Must be compatible with ``x1`` (see :ref:`broadcasting`). Should have a numeric data type. + + Returns + ------- + out: array + an array containing the element-wise differences. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + - At least one of ``x1`` or ``x2`` must be an array. + - The result of ``x1_i - x2_i`` must be the same as ``x1_i + (-x2_i)`` and must be governed by the same floating-point rules as addition (see :meth:`add`). + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Added scalar argument support. + """ + + +def tan(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the tangent for each element ``x_i`` of the input array ``x``. + + Each element ``x_i`` is assumed to be expressed in radians. + + .. note:: + Tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the real component and has first order poles along the real line at coordinates :math:`(\pi (\frac{1}{2} + n), 0)`. However, IEEE 754 binary floating-point representation cannot represent the value :math:`\pi / 2` exactly, and, thus, no argument value is possible for which a pole error occurs. + + .. note:: + For complex arguments, the mathematical definition of tangent is + + .. math:: + \begin{align} \operatorname{tan}(x) &= \frac{j(e^{-jx} - e^{jx})}{e^{-jx} + e^{jx}} \\ &= (-1) \frac{j(e^{jx} - e^{-jx})}{e^{jx} + e^{-jx}} \\ &= -j \cdot \operatorname{tanh}(jx) \end{align} + + where :math:`\operatorname{tanh}` is the hyperbolic tangent. + + Parameters + ---------- + x: array + input array whose elements are expressed in radians. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is either ``+infinity`` or ``-infinity``, the result is ``NaN``. + + For complex floating-point operands, special cases must be handled as if the operation is implemented as ``-1j * tanh(x*1j)``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tanh(x: array, /) -> array: + r""" + Calculates an implementation-dependent approximation to the hyperbolic tangent for each element ``x_i`` of the input array ``x``. + + The mathematical definition of the hyperbolic tangent is + + .. math:: + \begin{align} \operatorname{tanh}(x) &= \frac{\operatorname{sinh}(x)}{\operatorname{cosh}(x)} \\ &= \frac{e^x - e^{-x}}{e^x + e^{-x}} \end{align} + + where :math:`\operatorname{sinh}(x)` is the hyperbolic sine and :math:`\operatorname{cosh}(x)` is the hyperbolic cosine. + + .. note:: + The hyperbolic tangent is an analytical function on the complex plane and has no branch cuts. The function is periodic, with period :math:`\pi j`, with respect to the imaginary component and has first order poles along the imaginary line at coordinates :math:`(0, \pi (\frac{1}{2} + n))`. However, IEEE 754 binary floating-point representation cannot represent :math:`\pi / 2` exactly, and, thus, no argument value is possible such that a pole error occurs. + + Parameters + ---------- + x: array + input array whose elements each represent a hyperbolic angle. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the hyperbolic tangent of each element in ``x``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Special cases** + + .. note:: + For all operands, ``tanh(-x)`` must equal ``-tanh(x)``. + + For real-valued floating-point operands, + + - If ``x_i`` is ``NaN``, the result is ``NaN``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``+infinity``, the result is ``+1``. + - If ``x_i`` is ``-infinity``, the result is ``-1``. + + For complex floating-point operands, let ``a = real(x_i)``, ``b = imag(x_i)``, and + + .. note:: + For complex floating-point operands, ``tanh(conj(x))`` must equal ``conj(tanh(x))``. + + - If ``a`` is ``+0`` and ``b`` is ``+0``, the result is ``+0 + 0j``. + - If ``a`` is a nonzero finite number and ``b`` is ``+infinity``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``+infinity``, the result is ``+0 + NaN j``. + - If ``a`` is a nonzero finite number and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + - If ``a`` is ``+0`` and ``b`` is ``NaN``, the result is ``+0 + NaN j``. + - If ``a`` is ``+infinity`` and ``b`` is a positive (i.e., greater than ``0``) finite number, the result is ``1 + 0j``. + - If ``a`` is ``+infinity`` and ``b`` is ``+infinity``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``+infinity`` and ``b`` is ``NaN``, the result is ``1 + 0j`` (sign of the imaginary component is unspecified). + - If ``a`` is ``NaN`` and ``b`` is ``+0``, the result is ``NaN + 0j``. + - If ``a`` is ``NaN`` and ``b`` is a nonzero number, the result is ``NaN + NaN j``. + - If ``a`` is ``NaN`` and ``b`` is ``NaN``, the result is ``NaN + NaN j``. + + .. warning:: + For historical reasons stemming from the C standard, array libraries may not return the expected result when ``a`` is ``+0`` and ``b`` is either ``+infinity`` or ``NaN``. The result should be ``+0 + NaN j`` in both cases; however, for libraries compiled against older C versions, the result may be ``NaN + NaN j``. + + Array libraries are not required to patch these older C versions, and, thus, users are advised that results may vary across array library implementations for these special cases. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def trunc(x: array, /) -> array: + """ + Rounds each element ``x_i`` of the input array ``x`` to the nearest integer-valued number that is closer to zero than ``x_i``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + + Returns + ------- + out: array + an array containing the rounded result for each element in ``x``. The returned array must have the same data type as ``x``. + + Notes + ----- + + **Special cases** + + - If ``x_i`` is already integer-valued, the result is ``x_i``. + + For floating-point operands, + + - If ``x_i`` is ``+infinity``, the result is ``+infinity``. + - If ``x_i`` is ``-infinity``, the result is ``-infinity``. + - If ``x_i`` is ``+0``, the result is ``+0``. + - If ``x_i`` is ``-0``, the result is ``-0``. + - If ``x_i`` is ``NaN``, the result is ``NaN``. + """ diff --git a/src/array_api_stubs/_2024_12/fft.py b/src/array_api_stubs/_2024_12/fft.py new file mode 100644 index 000000000..0924b2f9c --- /dev/null +++ b/src/array_api_stubs/_2024_12/fft.py @@ -0,0 +1,707 @@ +__all__ = [ + "fft", + "ifft", + "fftn", + "ifftn", + "rfft", + "irfft", + "rfftn", + "irfftn", + "hfft", + "ihfft", + "fftfreq", + "rfftfreq", + "fftshift", + "ifftshift", +] + +from ._types import Tuple, Union, Sequence, array, Optional, Literal, dtype, device + + +def fft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifft(fft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (number of elements, axis, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def fftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def ifftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse discrete Fourier transform. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``ifftn(fftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (sizes, axes, and normalization mode). + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along the axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + specify the normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimensions) specified by ``axes``. The returned array must have the same data type as ``x`` and must have the same shape as ``x``, except for the axes specified by ``axes`` which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array have a complex floating-point data type and required that the output array have the same data type as the input array. + """ + + +def rfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse of ``rfft`` for complex-valued input. + + .. note:: + Applying the one-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfft(rfft(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axis and normalization mode) and consistent values for the number of elements over which to compute the transforms. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to size ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the transformed axis, the function must be provided an odd integer for ``n``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def rfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional discrete Fourier transform for real-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + s: Optional[Sequence[int]] + number of elements over which to compute the transform along axes (dimensions) specified by ``axes``. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``. + + - If ``s[i]`` is greater than ``M[i]``, axis ``i`` must be zero-padded to size ``s[i]``. + - If ``s[i]`` is less than ``M[i]``, axis ``i`` must be trimmed to size ``s[i]``. + - If ``s[i]`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + where ``n = prod(s)``, the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the last transformed axis which must have size ``s[-1]//2 + 1`` and the remaining transformed axes which must have size ``s[i]``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def irfftn( + x: array, + /, + *, + s: Optional[Sequence[int]] = None, + axes: Optional[Sequence[int]] = None, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the n-dimensional inverse of ``rfftn`` for complex-valued input. + + .. note:: + Applying the n-dimensional inverse discrete Fourier transform for real-valued input to the output of this function must return the original (i.e., non-transformed) input array within numerical accuracy (i.e., ``irfftn(rfftn(x)) == x``), provided that the transform and inverse transform are performed with the same arguments (axes and normalization mode) and consistent sizes. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + s: Optional[Sequence[int]] + number of elements along the transformed axes (dimensions) specified by ``axes`` in the **output array**. Let ``i`` be the index of the ``n``-th axis specified by ``axes`` (i.e., ``i = axes[n]``) and ``M[i]`` be the size of the input array along axis ``i``. When ``s`` is ``None``, the function must set ``s`` equal to a sequence of integers such that ``s[i]`` equals ``M[i]`` for all ``i``, except for the last transformed axis in which ``s[i]`` equals ``2*(M[i]-1)``. For each ``i``, let ``n`` equal ``s[i]``, except for the last transformed axis in which ``n`` equals ``s[i]//2+1``. + + - If ``n`` is greater than ``M[i]``, axis ``i`` of the input array must be zero-padded to size ``n``. + - If ``n`` is less than ``M[i]``, axis ``i`` of the input array must be trimmed to size ``n``. + - If ``n`` equals ``M[i]`` or ``-1``, all elements along axis ``i`` of the input array must be used when computing the transform. + + If ``s`` is not ``None``, ``axes`` must not be ``None``. Default: ``None``. + axes: Optional[Sequence[int]] + axes (dimensions) over which to compute the transform. A valid axis in ``axes`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an axis is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). + + If ``s`` is provided, the corresponding ``axes`` to be transformed must also be provided. If ``axes`` is ``None``, the function must compute the transform over all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + where ``n = prod(s)`` is the logical FFT size. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axes (dimension) specified by ``axes``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the transformed axes which must have size ``s[i]``. + + Notes + ----- + + - In order to return an array having an odd number of elements along the last transformed axis, the function must be provided an odd integer for ``s[-1]``. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have a real-valued floating-point data type having the same precision as the input array. + """ + + +def hfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Should have a complex floating-point data type. + n: Optional[int] + number of elements along the transformed axis (dimension) specified by ``axis`` in the **output array**. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``2*(M-1)``. + + - If ``n//2+1`` is greater than ``M``, the axis of the input array specified by ``axis`` must be zero-padded to length ``n//2+1``. + - If ``n//2+1`` is less than ``M``, the axis of the input array specified by ``axis`` must be trimmed to size ``n//2+1``. + - If ``n//2+1`` equals ``M``, all elements along the axis of the input array specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: no normalization. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: normalize by ``1/n``. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n``. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the input array to have a complex floating-point data type and required that the output array have a real-valued data type having the same precision as the input array. + """ + + +def ihfft( + x: array, + /, + *, + n: Optional[int] = None, + axis: int = -1, + norm: Literal["backward", "ortho", "forward"] = "backward", +) -> array: + """ + Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. + + Parameters + ---------- + x: array + input array. Must have a real-valued floating-point data type. + n: Optional[int] + number of elements over which to compute the transform along the axis (dimension) specified by ``axis``. Let ``M`` be the size of the input array along the axis specified by ``axis``. When ``n`` is ``None``, the function must set ``n`` equal to ``M``. + + - If ``n`` is greater than ``M``, the axis specified by ``axis`` must be zero-padded to size ``n``. + - If ``n`` is less than ``M``, the axis specified by ``axis`` must be trimmed to size ``n``. + - If ``n`` equals ``M``, all elements along the axis specified by ``axis`` must be used when computing the transform. + + Default: ``None``. + axis: int + axis (dimension) of the input array over which to compute the transform. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute the transform by counting backward from the last dimension (where ``-1`` refers to the last dimension). Default: ``-1``. + norm: Literal['backward', 'ortho', 'forward'] + normalization mode. Should be one of the following modes: + + - ``'backward'``: normalize by ``1/n``. + - ``'ortho'``: normalize by ``1/sqrt(n)`` (i.e., make the FFT orthonormal). + - ``'forward'``: no normalization. + + Default: ``'backward'``. + + Returns + ------- + out: array + an array transformed along the axis (dimension) specified by ``axis``. The returned array must have a complex floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``float64``, then the returned array must have a ``complex128`` data type). The returned array must have the same shape as ``x``, except for the axis specified by ``axis`` which must have size ``n//2 + 1``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def fftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Computes the discrete Fourier transform sample frequencies. + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, -n/2, ..., -1] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2, -(n-1)/2, ..., -1] / (d*n) # if n is odd + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n,)`` containing the sample frequencies. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. + """ + + +def rfftfreq( + n: int, + /, + *, + d: float = 1.0, + dtype: Optional[dtype] = None, + device: Optional[device] = None, +) -> array: + """ + Computes the discrete Fourier transform sample frequencies (for ``rfft`` and ``irfft``). + + For a Fourier transform of length ``n`` and length unit of ``d``, the frequencies are described as: + + .. code-block:: + + f = [0, 1, ..., n/2-1, n/2] / (d*n) # if n is even + f = [0, 1, ..., (n-1)/2-1, (n-1)/2] / (d*n) # if n is odd + + The Nyquist frequency component is considered to be positive. + + Parameters + ---------- + n: int + window length. + d: float + sample spacing between individual samples of the Fourier transform input. Default: ``1.0``. + dtype: Optional[dtype] + output array data type. Must be a real-valued floating-point data type. If ``dtype`` is ``None``, the output array data type must be the default real-valued floating-point data type. Default: ``None``. + device: Optional[device] + device on which to place the created array. Default: ``None``. + + Returns + ------- + out: array + an array of shape ``(n//2+1,)`` containing the sample frequencies. + + Notes + ----- + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Required the output array have the default real-valued floating-point data type. + + .. versionchanged:: 2024.12 + Added ``dtype`` keyword argument support. + """ + + +def fftshift(x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None) -> array: + """ + Shifts the zero-frequency component to the center of the spectrum. + + This function swaps half-spaces for all axes (dimensions) specified by ``axes``. + + .. note:: + ``out[0]`` is the Nyquist component only if the length of the input is even. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ + + +def ifftshift( + x: array, /, *, axes: Optional[Union[int, Sequence[int]]] = None +) -> array: + """ + Inverse of ``fftshift``. + + .. note:: + Although identical for even-length ``x``, ``fftshift`` and ``ifftshift`` differ by one sample for odd-length ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axes: Optional[Union[int, Sequence[int]]] + axes over which to perform the inverse shift. If ``None``, the function must shift all axes. Default: ``None``. + + If ``axes`` contains two or more entries which resolve to the same axis (i.e., resolved axes are not unique), the behavior is unspecified and thus implementation-defined. + + Returns + ------- + out: array + the shifted array. The returned array must have the same data type and shape as ``x``. + + Notes + ----- + + .. versionadded:: 2022.12 + """ diff --git a/src/array_api_stubs/_2024_12/indexing_functions.py b/src/array_api_stubs/_2024_12/indexing_functions.py new file mode 100644 index 000000000..8e4fae25f --- /dev/null +++ b/src/array_api_stubs/_2024_12/indexing_functions.py @@ -0,0 +1,70 @@ +__all__ = ["take", "take_along_axis"] + +from ._types import Union, Optional, array + + +def take(x: array, indices: array, /, *, axis: Optional[int] = None) -> array: + """ + Returns elements of an array along an axis. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). + indices: array + array indices. The array must be one-dimensional and have an integer data type. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). + axis: Optional[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 (where ``-1`` refers to 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 + 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``. + + Notes + ----- + + - 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. + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + .. versionadded:: 2022.12 + + .. versionchanged:: 2023.12 + Out-of-bounds behavior is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Behavior when provided a zero-dimensional input array is explicitly left unspecified. + + .. versionchanged:: 2024.12 + Clarified support for negative indices. + """ + + +def take_along_axis(x: array, indices: array, /, *, axis: int = -1) -> array: + """ + Returns elements from an array at the one-dimensional indices specified by ``indices`` along a provided ``axis``. + + Parameters + ---------- + x: array + input array. Must be compatible with ``indices``, except for the axis (dimension) specified by ``axis`` (see :ref:`broadcasting`). + indices: array + array indices. Must have the same rank (i.e., number of dimensions) as ``x``. If an index is negative, the function must determine the element to select along a specified axis (dimension) by counting from the last element (where ``-1`` refers to the last element). + axis: int + axis along 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 (where ``-1`` refers to the last dimension). Default: ``-1``. + + Returns + ------- + out: array + an array having the same data type as ``x``. Must have the same rank (i.e., number of dimensions) as ``x`` and must have a shape determined according to :ref:`broadcasting`, except for the axis (dimension) specified by ``axis`` whose size must equal the size of the corresponding axis (dimension) in ``indices``. + + Notes + ----- + + - This specification does not require bounds checking. The behavior for out-of-bounds indices is left unspecified. + + .. versionadded:: 2024.12 + """ diff --git a/src/array_api_stubs/_2024_12/info.py b/src/array_api_stubs/_2024_12/info.py new file mode 100644 index 000000000..fc8b302a8 --- /dev/null +++ b/src/array_api_stubs/_2024_12/info.py @@ -0,0 +1,203 @@ +__all__ = [ + "__array_namespace_info__", + "capabilities", + "default_device", + "default_dtypes", + "devices", + "dtypes", +] + +from ._types import ( + Optional, + Union, + Tuple, + List, + device, + dtype, + DefaultDataTypes, + DataTypes, + Capabilities, + Info, +) + + +def __array_namespace_info__() -> Info: + """ + Returns a namespace with Array API namespace inspection utilities. + + See :ref:`inspection` for a list of inspection APIs. + + Returns + ------- + out: Info + An object containing Array API namespace inspection utilities. + + Notes + ----- + + The returned object may be either a namespace or a class, so long as an Array API user can access inspection utilities as follows: + + :: + + info = xp.__array_namespace_info__() + info.capabilities() + info.devices() + info.dtypes() + info.default_dtypes() + # ... + + .. versionadded: 2023.12 + """ + + +def capabilities() -> Capabilities: + """ + Returns a dictionary of array library capabilities. + + The dictionary must contain the following keys: + + - `"boolean indexing"`: boolean indicating whether an array library supports boolean indexing. If a conforming implementation fully supports boolean indexing in compliance with this specification (see :ref:`indexing`), the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"data-dependent shapes"`: boolean indicating whether an array library supports data-dependent output shapes. If a conforming implementation fully supports all APIs included in this specification (excluding boolean indexing) which have data-dependent output shapes, as explicitly demarcated throughout the specification, the corresponding dictionary value must be ``True``; otherwise, the value must be ``False``. + - `"max dimensions"`: maximum number of supported dimensions. If a conforming implementation supports arrays having an arbitrary number of dimensions (potentially infinite), the corresponding dictionary value must be ``None``; otherwise, the value must be a finite integer. + + Returns + ------- + out: Capabilities + a dictionary of array library capabilities. + + Notes + ----- + + .. versionadded: 2023.12 + + .. versionchanged:: 2024.12 + Added support for querying the maximum number of supported dimensions. + """ + + +def default_device() -> device: + """ + Returns the default device. + + Returns + ------- + out: device + an object corresponding to the default device. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def default_dtypes( + *, + device: Optional[device] = None, +) -> DefaultDataTypes: + """ + Returns a dictionary containing default data types. + + The dictionary must have the following keys: + + - `"real floating"`: default real floating-point data type. + - `"complex floating"`: default complex floating-point data type. + - `"integral"`: default integral data type. + - `"indexing"`: default array index data type. + + Dictionary values must be the corresponding data type object. + + Parameters + ---------- + device: Optional[device] + device for which to return default data types. If ``device`` is ``None``, the returned data types must be the default data types for the current device; otherwise, the returned data types must be default data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the default data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the default data types for the default device. + + Returns + ------- + out: DefaultDataTypes + a dictionary containing the default data type for respective data type kinds. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def dtypes( + *, + device: Optional[device] = None, + kind: Optional[Union[str, Tuple[str, ...]]] = None, +) -> DataTypes: + """ + Returns a dictionary of supported *Array API* data types. + + .. note:: + While specification-conforming array libraries may support additional data types which are not present in this specification, data types which are not present in this specification should not be included in the returned dictionary. + + .. note:: + Specification-conforming array libraries must only return supported data types having expected properties as described in :ref:`data-types`. For example, if a library decides to alias ``float32`` as ``float64``, that library must not include ``float64`` in the dictionary of supported data types. + + Parameters + ---------- + kind: Optional[Union[str, Tuple[str, ...]]] + data type kind. + + - If ``kind`` is ``None``, the function must return a dictionary containing all supported Array API data types. + + - If ``kind`` is a string, the function must return a dictionary containing the data types belonging to the specified data type kind. The following data type kinds must be supported: + + - ``'bool'``: boolean data types (e.g., ``bool``). + - ``'signed integer'``: signed integer data types (e.g., ``int8``, ``int16``, ``int32``, ``int64``). + - ``'unsigned integer'``: unsigned integer data types (e.g., ``uint8``, ``uint16``, ``uint32``, ``uint64``). + - ``'integral'``: integer data types. Shorthand for ``('signed integer', 'unsigned integer')``. + - ``'real floating'``: real-valued floating-point data types (e.g., ``float32``, ``float64``). + - ``'complex floating'``: complex floating-point data types (e.g., ``complex64``, ``complex128``). + - ``'numeric'``: numeric data types. Shorthand for ``('integral', 'real floating', 'complex floating')``. + + - If ``kind`` is a tuple, the tuple specifies a union of data type kinds, and the function must return a dictionary containing the data types belonging to at least one of the specified data type kinds. + + Default: ``None``. + device: Optional[device] + device for which to return supported data types. If ``device`` is ``None``, the returned data types must be the supported data types for the current device; otherwise, the returned data types must be supported data types specific to the specified device. Default: ``None``. + + .. note:: + Some array libraries have the concept of a device context manager, allowing library consumers to manage the current device context. When ``device`` is ``None``, libraries supporting a device context should return the supported data types for the current device. For libraries without a context manager or supporting only a single device, those libraries should return the supported data types for the default device. + + Returns + ------- + out: DataTypes + a dictionary containing supported data types. + + .. note:: + Dictionary keys must only consist of canonical names as defined in :ref:`data-types`. + + Notes + ----- + + .. versionadded: 2023.12 + """ + + +def devices() -> List[device]: + """ + Returns a list of supported devices which are available at runtime. + + Returns + ------- + out: List[device] + a list of supported devices. + + Notes + ----- + + Each device object (see :ref:`device-support`) in the list of returned devices must be an object which can be provided as a valid keyword-argument to array creation functions. + + Notes + ----- + + .. versionadded: 2023.12 + """ diff --git a/src/array_api_stubs/_2024_12/linalg.py b/src/array_api_stubs/_2024_12/linalg.py new file mode 100644 index 000000000..4086c333e --- /dev/null +++ b/src/array_api_stubs/_2024_12/linalg.py @@ -0,0 +1,853 @@ +__all__ = [ + "cholesky", + "cross", + "det", + "diagonal", + "eigh", + "eigvalsh", + "inv", + "matmul", + "matrix_norm", + "matrix_power", + "matrix_rank", + "matrix_transpose", + "outer", + "pinv", + "qr", + "slogdet", + "solve", + "svd", + "svdvals", + "tensordot", + "trace", + "vecdot", + "vector_norm", +] + + +from ._types import Literal, Optional, Tuple, Union, Sequence, array, dtype +from .constants import inf + + +def cholesky(x: array, /, *, upper: bool = False) -> array: + r""" + Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The lower **Cholesky decomposition** of a complex Hermitian or real symmetric positive-definite matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = LL^{H} \qquad \text{L $\in\ \mathbb{K}^{n \times n}$} + + where :math:`L` is a lower triangular matrix and :math:`L^{H}` is the conjugate transpose when :math:`L` is complex-valued and the transpose when :math:`L` is real-valued. + + The upper Cholesky decomposition is defined similarly + + .. math:: + x = U^{H}U \qquad \text{U $\in\ \mathbb{K}^{n \times n}$} + + where :math:`U` is an upper triangular matrix. + + When ``x`` is a stack of matrices, the function must compute the Cholesky decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric positive-definite matrix (or a stack of matrices) is implementation-defined. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square complex Hermitian or real symmetric positive-definite matrices. Should have a floating-point data type. + upper: bool + If ``True``, the result must be the upper-triangular Cholesky factor :math:`U`. If ``False``, the result must be the lower-triangular Cholesky factor :math:`L`. Default: ``False``. + + Returns + ------- + out: array + an array containing the Cholesky factors for each square matrix. If ``upper`` is ``False``, the returned array must contain lower-triangular matrices; otherwise, the returned array must contain upper-triangular matrices. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def cross(x1: array, x2: array, /, *, axis: int = -1) -> array: + """ + Returns the cross product of 3-element vectors. + + If ``x1`` and/or ``x2`` are multi-dimensional arrays (i.e., the broadcasted result has a rank greater than ``1``), then the cross-product of each pair of corresponding 3-element vectors is independently computed. + + Parameters + ---------- + x1: array + first input array. Must have a numeric data type. The size of the axis over which the cross product is to be computed must be equal to 3. + x2: array + second input array. Must be broadcast compatible with ``x1`` along all axes other than the axis along which the cross-product is computed (see :ref:`broadcasting`). The size of the axis over which the cross product is to be computed must be equal to 3. Must have a numeric data type. + + .. note:: + The compute axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the cross product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the cross product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the cross product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + an array containing the cross products. The returned array must have a data type determined by :ref:`type-promotion`. + + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the cross product is not equal to ``3`` (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added support for broadcasting. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted broadcasting to only non-compute axes and required that ``axis`` be a negative integer. + """ + + +def det(x: array, /) -> array: + """ + Returns the determinant of a square matrix (or a stack of square matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + if ``x`` is a two-dimensional array, a zero-dimensional array containing the determinant; otherwise, a non-zero dimensional array containing the determinant for each square matrix. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def diagonal(x: array, /, *, offset: int = 0) -> array: + """ + Returns the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: `0`. + + Returns + ------- + out: array + an array containing the diagonals and whose shape is determined by removing the last two dimensions and appending a dimension equal to the size of the resulting diagonals. The returned array must have the same data type as ``x``. + """ + + +def eigh(x: array, /) -> Tuple[array]: + r""" + Returns an eigenvalue decomposition of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalue decomposition** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = Q \Lambda Q^H + + with :math:`Q \in \mathbb{K}^{n \times n}` and :math:`\Lambda \in \mathbb{R}^n` and where :math:`Q^H` is the conjugate transpose when :math:`Q` is complex and the transpose when :math:`Q` is real-valued and :math:`\Lambda` is a diagonal matrix whose diagonal elements are the corresponding eigenvalues. When ``x`` is real-valued, :math:`Q` is orthogonal, and, when ``x`` is complex, :math:`Q` is unitary. + + .. note:: + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. warning:: + The eigenvectors of a symmetric matrix are not unique and are not continuous with respect to ``x``. Because eigenvectors are not unique, different hardware and software may compute different eigenvectors. + + Non-uniqueness stems from the fact that multiplying an eigenvector by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another set of valid eigenvectors. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eig`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array] + a namedtuple (``eigenvalues``, ``eigenvectors``) whose + + - first element must have the field name ``eigenvalues`` (corresponding to :math:`\operatorname{diag}\Lambda` above) and must be an array consisting of computed eigenvalues. The array containing the eigenvalues must have shape ``(..., M)`` and must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then ``eigenvalues`` must be ``float64``). + - second element have have the field name ``eigenvectors`` (corresponding to :math:`Q` above) and must be an array where the columns of the inner most matrices contain the computed eigenvectors. These matrices must be orthogonal. The array containing the eigenvectors must have shape ``(..., M, M)`` and must have the same data type as ``x``. + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def eigvalsh(x: array, /) -> array: + r""" + Returns the eigenvalues of a complex Hermitian or real symmetric matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **eigenvalues** of a complex Hermitian or real symmetric matrix :math:`x \in\ \mathbb{K}^{n \times n}` are defined as the roots (counted with multiplicity) of the polynomial :math:`p` of degree :math:`n` given by + + .. math:: + p(\lambda) = \operatorname{det}(x - \lambda I_n) + + where :math:`\lambda \in \mathbb{R}` and where :math:`I_n` is the *n*-dimensional identity matrix. + + .. note:; + The eigenvalues of a complex Hermitian or real symmetric matrix are always real. + + .. note:: + Whether an array library explicitly checks whether an input array is Hermitian or a symmetric matrix (or a stack of matrices) is implementation-defined. + + .. note:: + The function ``eigvals`` will be added in a future version of the specification. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the computed eigenvalues. The returned array must have shape ``(..., M)`` and have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then must have a ``float64`` data type). + + Notes + ----- + + .. note:: + Eigenvalue sort order is left unspecified and is thus implementation-dependent. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def inv(x: array, /) -> array: + r""" + Returns the multiplicative inverse of a square matrix (or a stack of square matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **inverse matrix** :math:`x^{-1} \in\ \mathbb{K}^{n \times n}` of a square matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x^{-1}x = xx^{-1} = I_n + + where :math:`I_n` is the *n*-dimensional identity matrix. + + The inverse matrix exists if and only if ``x`` is invertible. When ``x`` is invertible, the inverse is unique. + + When ``x`` is a stack of matrices, the function must compute the inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the multiplicative inverses. The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have the same shape as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matmul(x1: array, x2: array, /) -> array: + """Alias for :func:`~array_api.matmul`.""" + + +def matrix_norm( + x: array, + /, + *, + keepdims: bool = False, + ord: Optional[Union[int, float, Literal[inf, -inf, "fro", "nuc"]]] = "fro", +) -> array: + """ + Computes the matrix norm of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + keepdims: bool + If ``True``, the last two axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the last two axes (dimensions) must not be included in the result. Default: ``False``. + ord: Optional[Union[int, float, Literal[inf, -inf, 'fro', 'nuc']]] + order of the norm. The following mathematical norms must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | 'fro' | Frobenius norm | + +------------------+---------------------------------+ + | 'nuc' | nuclear norm | + +------------------+---------------------------------+ + | 1 | max(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | 2 | largest singular value | + +------------------+---------------------------------+ + | inf | max(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+---------------------------------+ + | ord | description | + +==================+=================================+ + | -1 | min(sum(abs(x), axis=0)) | + +------------------+---------------------------------+ + | -2 | smallest singular value | + +------------------+---------------------------------+ + | -inf | min(sum(abs(x), axis=1)) | + +------------------+---------------------------------+ + + If ``ord=1``, the norm corresponds to the induced matrix norm where ``p=1`` (i.e., the maximum absolute value column sum). + + If ``ord=2``, the norm corresponds to the induced matrix norm where ``p=inf`` (i.e., the maximum absolute value row sum). + + If ``ord=inf``, the norm corresponds to the induced matrix norm where ``p=2`` (i.e., the largest singular value). + + Default: ``'fro'``. + + Returns + ------- + out: array + an array containing the norms for each ``MxN`` matrix. If ``keepdims`` is ``False``, the returned array must have a rank which is two less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_power(x: array, n: int, /) -> array: + """ + Raises a square matrix (or a stack of square matrices) ``x`` to an integer power ``n``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + n: int + integer exponent. + + Returns + ------- + out: array + if ``n`` is equal to zero, an array containing the identity matrix for each square matrix. If ``n`` is less than zero, an array containing the inverse of each square matrix raised to the absolute value of ``n``, provided that each square matrix is invertible. If ``n`` is greater than zero, an array containing the result of raising each square matrix to the power ``n``. The returned array must have the same shape as ``x`` and a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_rank(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + """ + Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). + + When ``x`` is a stack of matrices, the function must compute the number of non-zero singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the ranks. The returned array must have the default integer data type and must have shape ``(...)`` (i.e., must have a shape equal to ``shape(x)[:-2]``). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def matrix_transpose(x: array, /) -> array: + """Alias for :func:`~array_api.matrix_transpose`.""" + + +def outer(x1: array, x2: array, /) -> array: + """ + Returns the outer product of two vectors ``x1`` and ``x2``. + + Parameters + ---------- + x1: array + first one-dimensional input array of size ``N``. Must have a numeric data type. + x2: array + second one-dimensional input array of size ``M``. Must have a numeric data type. + + Returns + ------- + out: array + a two-dimensional array containing the outer product and whose shape is ``(N, M)``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def pinv(x: array, /, *, rtol: Optional[Union[float, array]] = None) -> array: + r""" + Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) ``x``. + + The pseudo-inverse of a matrix :math:`A`, denoted :math:`A^{+}`, is defined as the matrix that "solves" the least-squares problem :math:`Ax = b` (i.e., if :math:`\overline{x}` is a solution, then :math:`A^{+}` is the matrix such that :math:`\overline{x} = A^{+}b`). + + While the pseudo-inverse can be defined algebraically, one can understand the pseudo-inverse via singular value decomposition (SVD). Namely, if + + .. math:: + A = U \Sigma V^H + + is a singular decomposition of :math:`A`, then + + .. math:: + A^{+} = U \Sigma^{+} V^H + + where :math:`U` and :math:`V^H` are orthogonal matrices, :math:`\Sigma` is a diagonal matrix consisting of :math:`A`'s singular values, and :math:`\Sigma^{+}` is then a diagonal matrix consisting of the reciprocals of :math:`A`'s singular values, leaving zeros in place. During numerical computation, only elements larger than a small tolerance are considered nonzero, and all others replaced by zeros. + + When ``x`` is a stack of matrices, the function must compute the pseudo-inverse for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a floating-point data type. + rtol: Optional[Union[float, array]] + relative tolerance for small singular values. Singular values approximately less than or equal to ``rtol * largest_singular_value`` are set to zero. If a ``float``, the value is equivalent to a zero-dimensional array having a real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``) and must be broadcast against each matrix. If an ``array``, must have a real-valued floating-point data type and must be compatible with ``shape(x)[:-2]`` (see :ref:`broadcasting`). If ``None``, the default value is ``max(M, N) * eps``, where ``eps`` must be the machine epsilon associated with the real-valued floating-point data type determined by :ref:`type-promotion` (as applied to ``x``). Default: ``None``. + + Returns + ------- + out: array + an array containing the pseudo-inverse(s). The returned array must have a floating-point data type determined by :ref:`type-promotion` and must have shape ``(..., N, M)`` (i.e., must have the same shape as ``x``, except the innermost two dimensions must be transposed). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def qr( + x: array, /, *, mode: Literal["reduced", "complete"] = "reduced" +) -> Tuple[array, array]: + r""" + Returns the QR decomposition of a full column rank matrix (or a stack of matrices). + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The **complete QR decomposition** of a matrix :math:`x \in\ \mathbb{K}^{n \times n}` is defined as + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times m}` is orthogonal when ``x`` is real-valued and unitary when ``x`` is complex-valued and where :math:`R \in\ \mathbb{K}^{m \times n}` is an upper triangular matrix with real diagonal (even when ``x`` is complex-valued). + + When :math:`m \gt n` (tall matrix), as :math:`R` is upper triangular, the last :math:`m - n` rows are zero. In this case, the last :math:`m - n` columns of :math:`Q` can be dropped to form the **reduced QR decomposition**. + + .. math:: + x = QR + + where :math:`Q \in\ \mathbb{K}^{m \times n}` and :math:`R \in\ \mathbb{K}^{n \times n}`. + + The reduced QR decomposition equals with the complete QR decomposition when :math:`n \geq m` (wide matrix). + + When ``x`` is a stack of matrices, the function must compute the QR decomposition for each matrix in the stack. + + .. note:: + Whether an array library explicitly checks whether an input array is a full column rank matrix (or a stack of full column rank matrices) is implementation-defined. + + .. warning:: + The elements in the diagonal of :math:`R` are not necessarily positive. Accordingly, the returned QR decomposition is only unique up to the sign of the diagonal of :math:`R`, and different libraries or inputs on different devices may produce different valid decompositions. + + .. warning:: + The QR decomposition is only well-defined if the first ``k = min(m,n)`` columns of every matrix in ``x`` are linearly independent. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices of rank ``N``. Should have a floating-point data type. + mode: Literal['reduced', 'complete'] + decomposition mode. Should be one of the following modes: + + - ``'reduced'``: compute only the leading ``K`` columns of ``q``, such that ``q`` and ``r`` have dimensions ``(..., M, K)`` and ``(..., K, N)``, respectively, and where ``K = min(M, N)``. + - ``'complete'``: compute ``q`` and ``r`` with dimensions ``(..., M, M)`` and ``(..., M, N)``, respectively. + + Default: ``'reduced'``. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(Q, R)`` whose + + - first element must have the field name ``Q`` and must be an array whose shape depends on the value of ``mode`` and contain matrices with orthonormal columns. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, M)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input array ``x``. + - second element must have the field name ``R`` and must be an array whose shape depends on the value of ``mode`` and contain upper-triangular matrices. If ``mode`` is ``'complete'``, the array must have shape ``(..., M, N)``. If ``mode`` is ``'reduced'``, the array must have shape ``(..., K, N)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same size as those of the input ``x``. + + Each returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def slogdet(x: array, /) -> Tuple[array, array]: + r""" + Returns the sign and the natural logarithm of the absolute value of the determinant of a square matrix (or a stack of square matrices) ``x``. + + .. note:: + The purpose of this function is to calculate the determinant more accurately when the determinant is either very small or very large, as calling ``det`` may overflow or underflow. + + The sign of the determinant is given by + + .. math:: + \operatorname{sign}(\det x) = \begin{cases} + 0 & \textrm{if } \det x = 0 \\ + \frac{\det x}{|\det x|} & \textrm{otherwise} + \end{cases} + + where :math:`|\det x|` is the absolute value of the determinant of ``x``. + + When ``x`` is a stack of matrices, the function must compute the sign and natural logarithm of the absolute value of the determinant for each matrix in the stack. + + **Special Cases** + + For real-valued floating-point operands, + + - If the determinant is zero, the ``sign`` should be ``0`` and ``logabsdet`` should be ``-infinity``. + + For complex floating-point operands, + + - If the determinant is ``0 + 0j``, the ``sign`` should be ``0 + 0j`` and ``logabsdet`` should be ``-infinity + 0j``. + + .. note:: + Depending on the underlying algorithm, when the determinant is zero, the returned result may differ from ``-infinity`` (or ``-infinity + 0j``). In all cases, the determinant should be equal to ``sign * exp(logabsdet)`` (although, again, the result may be subject to numerical precision errors). + + Parameters + ---------- + x: array + input array having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Should have a floating-point data type. + + Returns + ------- + out: Tuple[array, array] + a namedtuple (``sign``, ``logabsdet``) whose + + - first element must have the field name ``sign`` and must be an array containing a number representing the sign of the determinant for each square matrix. Must have the same data type as ``x``. + - second element must have the field name ``logabsdet`` and must be an array containing the natural logarithm of the absolute value of the determinant for each square matrix. If ``x`` is real-valued, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` is complex, the returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``logabsdet`` must have a ``float32`` data type). + + Each returned array must have shape ``shape(x)[:-2]``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def solve(x1: array, x2: array, /) -> array: + r""" + Returns the solution of a square system of linear equations with a unique solution. + + Let ``x1`` equal :math:`A` and ``x2`` equal :math:`B`. If the promoted data type of ``x1`` and ``x2`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if the promoted data type of ``x1`` and ``x2`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + This function computes the solution :math:`X \in\ \mathbb{K}^{m \times k}` of the **linear system** associated to :math:`A \in\ \mathbb{K}^{m \times m}` and :math:`B \in\ \mathbb{K}^{m \times k}` and is defined as + + .. math:: + AX = B + + This system of linear equations has a unique solution if and only if :math:`A` is invertible. + + .. note:: + Whether an array library explicitly checks whether ``x1`` is invertible is implementation-defined. + + When ``x1`` and/or ``x2`` is a stack of matrices, the function must compute a solution for each matrix in the stack. + + Parameters + ---------- + x1: array + coefficient array ``A`` having shape ``(..., M, M)`` and whose innermost two dimensions form square matrices. Must be of full rank (i.e., all rows or, equivalently, columns must be linearly independent). Should have a floating-point data type. + x2: array + ordinate (or "dependent variable") array ``B``. If ``x2`` has shape ``(M,)``, ``x2`` is equivalent to an array having shape ``(..., M, 1)``. If ``x2`` has shape ``(..., M, K)``, each column ``k`` defines a set of ordinate values for which to compute a solution, and ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (see :ref:`broadcasting`). Should have a floating-point data type. + + Returns + ------- + out: array + an array containing the solution to the system ``AX = B`` for each square matrix. If ``x2`` has shape ``(M,)``, the returned array must have shape equal to ``shape(x1)[:-2] + shape(x2)[-1:]``. Otherwise, if ``x2`` has shape ``(..., M, K)```, the returned array must have shape equal to ``(..., M, K)``, where ``...`` refers to the result of broadcasting ``shape(x1)[:-2]`` and ``shape(x2)[:-2]``. The returned array must have a floating-point data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2024.12 + Clarified broadcasting semantics and the shape of the output array. + """ + + +def svd(x: array, /, *, full_matrices: bool = True) -> Tuple[array, array, array]: + r""" + Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) ``x``. + + If ``x`` is real-valued, let :math:`\mathbb{K}` be the set of real numbers :math:`\mathbb{R}`, and, if ``x`` is complex-valued, let :math:`\mathbb{K}` be the set of complex numbers :math:`\mathbb{C}`. + + The full **singular value decomposition** of an :math:`m \times n` matrix :math:`x \in\ \mathbb{K}^{m \times n}` is a factorization of the form + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times m}`, :math:`\Sigma \in\ \mathbb{K}^{m \times\ n}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}` with :math:`k = \operatorname{min}(m, n)`, :math:`V^H \in\ \mathbb{K}^{n \times n}`, and where :math:`V^H` is the conjugate transpose when :math:`V` is complex and the transpose when :math:`V` is real-valued. When ``x`` is real-valued, :math:`U`, :math:`V` (and thus :math:`V^H`) are orthogonal, and, when ``x`` is complex, :math:`U`, :math:`V` (and thus :math:`V^H`) are unitary. + + When :math:`m \gt n` (tall matrix), we can drop the last :math:`m - n` columns of :math:`U` to form the reduced SVD + + .. math:: + x = U \Sigma V^H + + where :math:`U \in\ \mathbb{K}^{m \times k}`, :math:`\Sigma \in\ \mathbb{K}^{k \times\ k}`, :math:`\operatorname{diag}(\Sigma) \in\ \mathbb{R}^{k}`, and :math:`V^H \in\ \mathbb{K}^{k \times n}`. In this case, :math:`U` and :math:`V` have orthonormal columns. + + Similarly, when :math:`n \gt m` (wide matrix), we can drop the last :math:`n - m` columns of :math:`V` to also form a reduced SVD. + + This function returns the decomposition :math:`U`, :math:`S`, and :math:`V^H`, where :math:`S = \operatorname{diag}(\Sigma)`. + + When ``x`` is a stack of matrices, the function must compute the singular value decomposition for each matrix in the stack. + + .. warning:: + The returned arrays :math:`U` and :math:`V` are neither unique nor continuous with respect to ``x``. Because :math:`U` and :math:`V` are not unique, different hardware and software may compute different singular vectors. + + Non-uniqueness stems from the fact that multiplying any pair of singular vectors :math:`u_k`, :math:`v_k` by :math:`-1` when ``x`` is real-valued and by :math:`e^{\phi j}` (:math:`\phi \in \mathbb{R}`) when ``x`` is complex produces another two valid singular vectors of the matrix. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + full_matrices: bool + If ``True``, compute full-sized ``U`` and ``Vh``, such that ``U`` has shape ``(..., M, M)`` and ``Vh`` has shape ``(..., N, N)``. If ``False``, compute on the leading ``K`` singular vectors, such that ``U`` has shape ``(..., M, K)`` and ``Vh`` has shape ``(..., K, N)`` and where ``K = min(M, N)``. Default: ``True``. + + Returns + ------- + out: Tuple[array, array, array] + a namedtuple ``(U, S, Vh)`` whose + + - first element must have the field name ``U`` and must be an array whose shape depends on the value of ``full_matrices`` and contain matrices with orthonormal columns (i.e., the columns are left singular vectors). If ``full_matrices`` is ``True``, the array must have shape ``(..., M, M)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., M, K)``, where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + - second element must have the field name ``S`` and must be an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, ``S`` must have a ``float32`` data type). + - third element must have the field name ``Vh`` and must be an array whose shape depends on the value of ``full_matrices`` and contain orthonormal rows (i.e., the rows are the right singular vectors and the array is the adjoint). If ``full_matrices`` is ``True``, the array must have shape ``(..., N, N)``. If ``full_matrices`` is ``False``, the array must have shape ``(..., K, N)`` where ``K = min(M, N)``. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. Must have the same data type as ``x``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def svdvals(x: array, /) -> array: + """ + Returns the singular values of a matrix (or a stack of matrices) ``x``. + + When ``x`` is a stack of matrices, the function must compute the singular values for each matrix in the stack. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form matrices on which to perform singular value decomposition. Should have a floating-point data type. + + Returns + ------- + out: array + an array with shape ``(..., K)`` that contains the vector(s) of singular values of length ``K``, where ``K = min(M, N)``. For each vector, the singular values must be sorted in descending order by magnitude, such that ``s[..., 0]`` is the largest value, ``s[..., 1]`` is the second largest value, et cetera. The first ``x.ndim-2`` dimensions must have the same shape as those of the input ``x``. The returned array must have a real-valued floating-point data type having the same precision as ``x`` (e.g., if ``x`` is ``complex64``, the returned array must have a ``float32`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """Alias for :func:`~array_api.tensordot`.""" + + +def trace(x: array, /, *, offset: int = 0, dtype: Optional[dtype] = None) -> array: + """ + Returns the sum along the specified diagonals of a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. Should have a numeric data type. + offset: int + offset specifying the off-diagonal relative to the main diagonal. + + - ``offset = 0``: the main diagonal. + - ``offset > 0``: off-diagonal above the main diagonal. + - ``offset < 0``: off-diagonal below the main diagonal. + + Default: ``0``. + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + Returns + ------- + out: array + an array containing the traces and whose shape is determined by removing the last two dimensions and storing the traces in the last array dimension. For example, if ``x`` has rank ``k`` and shape ``(I, J, K, ..., L, M, N)``, then an output array has rank ``k-2`` and shape ``(I, J, K, ..., L)`` where + + :: + + out[i, j, k, ..., l] = trace(a[i, j, k, ..., l, :, :]) + + The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: + """Alias for :func:`~array_api.vecdot`.""" + + +def vector_norm( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, + ord: Union[int, float, Literal[inf, -inf]] = 2, +) -> array: + r""" + Computes the vector norm of a vector (or batch of vectors) ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + If an integer, ``axis`` specifies the axis (dimension) along which to compute vector norms. If an n-tuple, ``axis`` specifies the axes (dimensions) along which to compute batched vector norms. If ``None``, the vector norm must be computed over all array values (i.e., equivalent to computing the vector norm of a flattened array). Negative indices must be supported. Default: ``None``. + keepdims: bool + If ``True``, the axes (dimensions) specified by ``axis`` must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the axes (dimensions) specified by ``axis`` must not be included in the result. Default: ``False``. + ord: Union[int, float, Literal[inf, -inf]] + order of the norm. The following mathematical norms must be supported: + + +------------------+----------------------------+ + | ord | description | + +==================+============================+ + | 1 | L1-norm (Manhattan) | + +------------------+----------------------------+ + | 2 | L2-norm (Euclidean) | + +------------------+----------------------------+ + | inf | infinity norm | + +------------------+----------------------------+ + | (int,float >= 1) | p-norm | + +------------------+----------------------------+ + + The following non-mathematical "norms" must be supported: + + +------------------+--------------------------------+ + | ord | description | + +==================+================================+ + | 0 | sum(a != 0) | + +------------------+--------------------------------+ + | -1 | 1./sum(1./abs(a)) | + +------------------+--------------------------------+ + | -2 | 1./sqrt(sum(1./abs(a)\*\*2)) | + +------------------+--------------------------------+ + | -inf | min(abs(a)) | + +------------------+--------------------------------+ + | (int,float < 1) | sum(abs(a)\*\*ord)\*\*(1./ord) | + +------------------+--------------------------------+ + + Default: ``2``. + + Returns + ------- + out: array + an array containing the vector norms. If ``axis`` is ``None``, the returned array must be a zero-dimensional array containing a vector norm. If ``axis`` is a scalar value (``int`` or ``float``), the returned array must have a rank which is one less than the rank of ``x``. If ``axis`` is a ``n``-tuple, the returned array must have a rank which is ``n`` less than the rank of ``x``. If ``x`` has a real-valued data type, the returned array must have a real-valued floating-point data type determined by :ref:`type-promotion`. If ``x`` has a complex-valued data type, the returned array must have a real-valued floating-point data type whose precision matches the precision of ``x`` (e.g., if ``x`` is ``complex128``, then the returned array must have a ``float64`` data type). + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ diff --git a/src/array_api_stubs/_2024_12/linear_algebra_functions.py b/src/array_api_stubs/_2024_12/linear_algebra_functions.py new file mode 100644 index 000000000..da4c97743 --- /dev/null +++ b/src/array_api_stubs/_2024_12/linear_algebra_functions.py @@ -0,0 +1,166 @@ +__all__ = ["matmul", "matrix_transpose", "tensordot", "vecdot"] + + +from ._types import Tuple, Union, Sequence, array + + +def matmul(x1: array, x2: array, /) -> array: + """ + Computes the matrix product. + + .. note:: + The ``matmul`` function must implement the same semantics as the built-in ``@`` operator (see `PEP 465 `_). + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. Must have at least one dimension. If ``x1`` is one-dimensional having shape ``(M,)`` and ``x2`` has more than one dimension, ``x1`` must be promoted to a two-dimensional array by prepending ``1`` to its dimensions (i.e., must have shape ``(1, M)``). After matrix multiplication, the prepended dimensions in the returned array must be removed. If ``x1`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x1)[:-2]`` must be compatible with ``shape(x2)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x1`` has shape ``(..., M, K)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + x2: array + second input array. Should have a numeric data type. Must have at least one dimension. If ``x2`` is one-dimensional having shape ``(N,)`` and ``x1`` has more than one dimension, ``x2`` must be promoted to a two-dimensional array by appending ``1`` to its dimensions (i.e., must have shape ``(N, 1)``). After matrix multiplication, the appended dimensions in the returned array must be removed. If ``x2`` has more than one dimension (including after vector-to-matrix promotion), ``shape(x2)[:-2]`` must be compatible with ``shape(x1)[:-2]`` (after vector-to-matrix promotion) (see :ref:`broadcasting`). If ``x2`` has shape ``(..., K, N)``, the innermost two dimensions form matrices on which to perform matrix multiplication. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the matrix product. + + Returns + ------- + out: array + - if both ``x1`` and ``x2`` are one-dimensional arrays having shape ``(N,)``, a zero-dimensional array containing the inner product as its only element. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, a two-dimensional array containing the `conventional matrix product `_ and having shape ``(M, N)``. + - if ``x1`` is a one-dimensional array having shape ``(K,)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., N)`` (i.e., prepended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a one-dimensional array having shape ``(K,)``, an array having shape ``(..., M)`` (i.e., appended dimensions during vector-to-matrix promotion must be removed) and containing the `conventional matrix product `_. + - if ``x1`` is a two-dimensional array having shape ``(M, K)`` and ``x2`` is an array having shape ``(..., K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if ``x1`` is an array having shape ``(..., M, K)`` and ``x2`` is a two-dimensional array having shape ``(K, N)``, an array having shape ``(..., M, N)`` and containing the `conventional matrix product `_ for each stacked matrix. + - if either ``x1`` or ``x2`` has more than two dimensions, an array having a shape determined by :ref:`broadcasting` ``shape(x1)[:-2]`` against ``shape(x2)[:-2]`` and containing the `conventional matrix product `_ for each stacked matrix. + + The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + **Raises** + + - if either ``x1`` or ``x2`` is a zero-dimensional array. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is a one-dimensional array having shape ``(K,)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is a one-dimensional array having shape ``(L,)``, and ``K != L``. + - if ``x1`` is an array having shape ``(..., M, K)``, ``x2`` is an array having shape ``(..., L, N)``, and ``K != L``. + + """ + + +def matrix_transpose(x: array, /) -> array: + """ + Transposes a matrix (or a stack of matrices) ``x``. + + Parameters + ---------- + x: array + input array having shape ``(..., M, N)`` and whose innermost two dimensions form ``MxN`` matrices. + + Returns + ------- + out: array + an array containing the transpose for each matrix and having shape ``(..., N, M)``. The returned array must have the same data type as ``x``. + """ + + +def tensordot( + x1: array, + x2: array, + /, + *, + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] = 2, +) -> array: + """ + Returns a tensor contraction of ``x1`` and ``x2`` over specific axes. + + .. note:: + The ``tensordot`` function corresponds to the generalized matrix product. + + Parameters + ---------- + x1: array + first input array. Should have a numeric data type. + x2: array + second input array. Should have a numeric data type. Corresponding contracted axes of ``x1`` and ``x2`` must be equal. + + .. note:: + Contracted axes (dimensions) must not be broadcasted. + + axes: Union[int, Tuple[Sequence[int], Sequence[int]]] + number of axes (dimensions) to contract or explicit sequences of axis (dimension) indices for ``x1`` and ``x2``, respectively. + + If ``axes`` is an ``int`` equal to ``N``, then contraction must be performed over the last ``N`` axes of ``x1`` and the first ``N`` axes of ``x2`` in order. The size of each corresponding axis (dimension) must match. Must be nonnegative. + + - If ``N`` equals ``0``, the result is the tensor (outer) product. + - If ``N`` equals ``1``, the result is the tensor dot product. + - If ``N`` equals ``2``, the result is the tensor double contraction (default). + + If ``axes`` is a tuple of two sequences ``(x1_axes, x2_axes)``, the first sequence must apply to ``x1`` and the second sequence to ``x2``. Both sequences must have the same length. Each axis (dimension) ``x1_axes[i]`` for ``x1`` must have the same size as the respective axis (dimension) ``x2_axes[i]`` for ``x2``. Each index referred to in a sequence must be unique. If ``x1`` has rank (i.e, number of dimensions) ``N``, a valid ``x1`` axis must reside on the half-open interval ``[-N, N)``. If ``x2`` has rank ``M``, a valid ``x2`` axis must reside on the half-open interval ``[-M, M)``. + + + .. note:: + If either ``x1`` or ``x2`` has a complex floating-point data type, neither argument must be complex-conjugated or transposed. If conjugation and/or transposition is desired, these operations should be explicitly performed prior to computing the generalized matrix product. + + Returns + ------- + out: array + an array containing the tensor contraction whose shape consists of the non-contracted axes (dimensions) of the first array ``x1``, followed by the non-contracted axes (dimensions) of the second array ``x2``. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Allow negative axes. + """ + + +def vecdot(x1: array, x2: array, /, *, axis: int = -1) -> array: + r""" + Computes the (vector) dot product of two arrays. + + Let :math:`\mathbf{a}` be a vector in ``x1`` and :math:`\mathbf{b}` be a corresponding vector in ``x2``. The dot product is defined as + + .. math:: + \mathbf{a} \cdot \mathbf{b} = \sum_{i=0}^{n-1} \overline{a_i}b_i + + over the dimension specified by ``axis`` and where :math:`n` is the dimension size and :math:`\overline{a_i}` denotes the complex conjugate if :math:`a_i` is complex and the identity if :math:`a_i` is real-valued. + + Parameters + ---------- + x1: array + first input array. Should have a floating-point data type. + x2: array + second input array. Must be compatible with ``x1`` for all non-contracted axes (see :ref:`broadcasting`). The size of the axis over which to compute the dot product must be the same size as the respective axis in ``x1``. Should have a floating-point data type. + + .. note:: + The contracted axis (dimension) must not be broadcasted. + + axis: int + the axis (dimension) of ``x1`` and ``x2`` containing the vectors for which to compute the dot product. Should be an integer on the interval ``[-N, -1]``, where ``N`` is ``min(x1.ndim, x2.ndim)``. The function must determine the axis along which to compute the dot product by counting backward from the last dimension (where ``-1`` refers to the last dimension). By default, the function must compute the dot product over the last axis. Default: ``-1``. + + Returns + ------- + out: array + if ``x1`` and ``x2`` are both one-dimensional arrays, a zero-dimensional containing the dot product; otherwise, a non-zero-dimensional array containing the dot products and having rank ``N-1``, where ``N`` is the rank (number of dimensions) of the shape determined according to :ref:`broadcasting` along the non-contracted axes. The returned array must have a data type determined by :ref:`type-promotion`. + + Notes + ----- + + **Raises** + + - if the size of the axis over which to compute the dot product is not the same (before broadcasting) for both ``x1`` and ``x2``. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Restricted ``axis`` to only negative integers. + """ diff --git a/src/array_api_stubs/_2024_12/manipulation_functions.py b/src/array_api_stubs/_2024_12/manipulation_functions.py new file mode 100644 index 000000000..dd8d4cd69 --- /dev/null +++ b/src/array_api_stubs/_2024_12/manipulation_functions.py @@ -0,0 +1,371 @@ +__all__ = [ + "broadcast_arrays", + "broadcast_to", + "concat", + "expand_dims", + "flip", + "moveaxis", + "permute_dims", + "repeat", + "reshape", + "roll", + "squeeze", + "stack", + "tile", + "unstack", +] + + +from ._types import List, Optional, Tuple, Union, array + + +def broadcast_arrays(*arrays: array) -> List[array]: + """ + Broadcasts one or more arrays against one another. + + Parameters + ---------- + arrays: array + an arbitrary number of to-be broadcasted arrays. + + Returns + ------- + out: List[array] + a list of broadcasted arrays. Each array must have the same shape. Each array must have the same dtype as its corresponding input array. + """ + + +def broadcast_to(x: array, /, shape: Tuple[int, ...]) -> array: + """ + Broadcasts an array to a specified shape. + + Parameters + ---------- + x: array + array to broadcast. Must be capable of being broadcast to the specified ``shape`` (see :ref:`broadcasting`). If the array is incompatible with the specified shape, the function must raise an exception. + shape: Tuple[int, ...] + array shape. + + Returns + ------- + out: array + an array having the specified shape. Must have the same data type as ``x``. + + .. versionchanged:: 2024.12 + Clarified broadcast behavior. + """ + + +def concat( + arrays: Union[Tuple[array, ...], List[array]], /, *, axis: Optional[int] = 0 +) -> array: + """ + Joins a sequence of arrays along an existing axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. The arrays must have the same shape, except in the dimension specified by ``axis``. + axis: Optional[int] + axis along which the arrays will be joined. If ``axis`` is ``None``, arrays must be flattened before concatenation. If ``axis`` is negative, the function must determine the axis along which to join by counting from the last dimension. Default: ``0``. + + Returns + ------- + out: array + an output array containing the concatenated values. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def expand_dims(x: array, /, *, axis: int = 0) -> array: + """ + Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by ``axis``. + + Parameters + ---------- + x: array + input array. + axis: int + axis position (zero-based). If ``x`` has rank (i.e, number of dimensions) ``N``, a valid ``axis`` must reside on the closed-interval ``[-N-1, N]``. If provided a negative ``axis``, the axis position at which to insert a singleton dimension must be computed as ``N + axis + 1``. Hence, if provided ``-1``, the resolved axis position must be ``N`` (i.e., a singleton dimension must be appended to the input array ``x``). If provided ``-N-1``, the resolved axis position must be ``0`` (i.e., a singleton dimension must be prepended to the input array ``x``). + + Returns + ------- + out: array + an expanded output array having the same data type as ``x``. + + Raises + ------ + IndexError + If provided an invalid ``axis`` position, an ``IndexError`` should be raised. + """ + + +def flip(x: array, /, *, axis: Optional[Union[int, Tuple[int, ...]]] = None) -> array: + """ + Reverses the order of elements in an array along the given axis. The shape of the array must be preserved. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which to flip. If ``axis`` is ``None``, the function must flip all input array axes. If ``axis`` is negative, the function must count from the last dimension. If provided more than one axis, the function must flip only the specified axes. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and shape as ``x`` and whose elements, relative to ``x``, are reordered. + """ + + +def moveaxis( + x: array, + source: Union[int, Tuple[int, ...]], + destination: Union[int, Tuple[int, ...]], + /, +) -> array: + """ + Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. + + Parameters + ---------- + x: array + input array. + source: Union[int, Tuple[int, ...]] + Axes to move. Provided axes must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + destination: Union[int, Tuple[int, ...]] + indices defining the desired positions for each respective ``source`` axis index. Provided indices must be unique. If ``x`` has rank (i.e, number of dimensions) ``N``, a valid axis must reside on the half-open interval ``[-N, N)``. + + Returns + ------- + out: array + an array containing reordered axes. The returned array must have the same data type as ``x``. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def permute_dims(x: array, /, axes: Tuple[int, ...]) -> array: + """ + Permutes the axes (dimensions) of an array ``x``. + + Parameters + ---------- + x: array + input array. + axes: Tuple[int, ...] + tuple containing a permutation of ``(0, 1, ..., N-1)`` where ``N`` is the number of axes (dimensions) of ``x``. + + Returns + ------- + out: array + an array containing the axes permutation. The returned array must have the same data type as ``x``. + """ + + +def repeat( + x: array, + repeats: Union[int, array], + /, + *, + axis: Optional[int] = None, +) -> array: + """ + Repeats each element of an array a specified number of times on a per-element basis. + + .. admonition:: Data-dependent output shape + :class: important + + When ``repeats`` is an array, the shape of the output array for this function depends on the data values in the ``repeats`` array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing the values in ``repeats``. Accordingly, such libraries may choose to omit support for ``repeats`` arrays; however, conforming implementations must support providing a literal ``int``. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array containing elements to repeat. + repeats: Union[int, array] + the number of repetitions for each element. + + If ``axis`` is ``None``, let ``N = prod(x.shape)`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(N,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(N,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape `(N,)`. + + If ``axis`` is not ``None``, let ``M = x.shape[axis]`` and + + - if ``repeats`` is an array, ``repeats`` must be broadcast compatible with the shape ``(M,)`` (i.e., be a one-dimensional array having shape ``(1,)`` or ``(M,)``). + - if ``repeats`` is an integer, ``repeats`` must be broadcasted to the shape ``(M,)``. + + If ``repeats`` is an array, the array must have an integer data type. + + .. note:: + For specification-conforming array libraries supporting hardware acceleration, providing an array for ``repeats`` may cause device synchronization due to an unknown output shape. For those array libraries where synchronization concerns are applicable, conforming array libraries are advised to include a warning in their documentation regarding potential performance degradation when ``repeats`` is an array. + + axis: Optional[int] + the axis (dimension) along which to repeat elements. If ``axis`` is `None`, the function must flatten the input array ``x`` and then repeat elements of the flattened input array and return the result as a one-dimensional output array. A flattened input array must be flattened in row-major, C-style order. Default: ``None``. + + Returns + ------- + out: array + an output array containing repeated elements. The returned array must have the same data type as ``x``. If ``axis`` is ``None``, the returned array must be a one-dimensional array; otherwise, the returned array must have the same shape as ``x``, except for the axis (dimension) along which elements were repeated. + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def reshape( + x: array, /, shape: Tuple[int, ...], *, copy: Optional[bool] = None +) -> array: + """ + Reshapes an array without changing its data. + + Parameters + ---------- + x: array + input array to reshape. + shape: Tuple[int, ...] + a new shape compatible with the original shape. One shape dimension is allowed to be ``-1``. When a shape dimension is ``-1``, the corresponding output array shape dimension must be inferred from the length of the array and the remaining dimensions. + copy: Optional[bool] + whether or not to copy the input array. If ``True``, the function must always copy (see :ref:`copy-keyword-argument`). If ``False``, the function must never copy. If ``None``, the function must avoid copying, if possible, and may copy otherwise. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If ``copy=False`` and a copy would be necessary, a ``ValueError`` + should be raised. + """ + + +def roll( + x: array, + /, + shift: Union[int, Tuple[int, ...]], + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, +) -> array: + """ + Rolls array elements along a specified axis. Array elements that roll beyond the last position are re-introduced at the first position. Array elements that roll beyond the first position are re-introduced at the last position. + + Parameters + ---------- + x: array + input array. + shift: Union[int, Tuple[int, ...]] + number of places by which the elements are shifted. If ``shift`` is a tuple, then ``axis`` must be a tuple of the same size, and each of the given axes must be shifted by the corresponding element in ``shift``. If ``shift`` is an ``int`` and ``axis`` a tuple, then the same ``shift`` must be used for all specified axes. If a shift is positive, then array elements must be shifted positively (toward larger indices) along the dimension of ``axis``. If a shift is negative, then array elements must be shifted negatively (toward smaller indices) along the dimension of ``axis``. + axis: Optional[Union[int, Tuple[int, ...]]] + axis (or axes) along which elements to shift. If ``axis`` is ``None``, the array must be flattened, shifted, and then restored to its original shape. Default: ``None``. + + Returns + ------- + out: array + an output array having the same data type as ``x`` and whose elements, relative to ``x``, are shifted. + """ + + +def squeeze(x: array, /, axis: Union[int, Tuple[int, ...]]) -> array: + """ + Removes singleton dimensions (axes) from ``x``. + + Parameters + ---------- + x: array + input array. + axis: Union[int, Tuple[int, ...]] + axis (or axes) to squeeze. + + Returns + ------- + out: array + an output array having the same data type and elements as ``x``. + + Raises + ------ + ValueError + If a specified axis has a size greater than one (i.e., it is not a + singleton dimension), a ``ValueError`` should be raised. + """ + + +def stack(arrays: Union[Tuple[array, ...], List[array]], /, *, axis: int = 0) -> array: + """ + Joins a sequence of arrays along a new axis. + + Parameters + ---------- + arrays: Union[Tuple[array, ...], List[array]] + input arrays to join. Each array must have the same shape. + axis: int + axis along which the arrays will be joined. Providing an ``axis`` specifies the index of the new axis in the dimensions of the result. For example, if ``axis`` is ``0``, the new axis will be the first dimension and the output array will have shape ``(N, A, B, C)``; if ``axis`` is ``1``, the new axis will be the second dimension and the output array will have shape ``(A, N, B, C)``; and, if ``axis`` is ``-1``, the new axis will be the last dimension and the output array will have shape ``(A, B, C, N)``. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: array + an output array having rank ``N+1``, where ``N`` is the rank (number of dimensions) of ``x``. If the input arrays have different data types, normal :ref:`type-promotion` must apply. If the input arrays have the same data type, the output array must have the same data type as the input arrays. + + .. note:: + This specification leaves type promotion between data type families (i.e., ``intxx`` and ``floatxx``) unspecified. + """ + + +def tile(x: array, repetitions: Tuple[int, ...], /) -> array: + """ + Constructs an array by tiling an input array. + + Parameters + ---------- + x: array + input array. + repetitions: Tuple[int, ...] + number of repetitions along each axis (dimension). + + Let ``N = len(x.shape)`` and ``M = len(repetitions)``. + + If ``N > M``, the function must prepend ones until all axes (dimensions) are specified (e.g., if ``x`` has shape ``(8,6,4,2)`` and ``repetitions`` is the tuple ``(3,3)``, then ``repetitions`` must be treated as ``(1,1,3,3)``). + + If ``N < M``, the function must prepend singleton axes (dimensions) to ``x`` until ``x`` has as many axes (dimensions) as ``repetitions`` specifies (e.g., if ``x`` has shape ``(4,2)`` and ``repetitions`` is the tuple ``(3,3,3,3)``, then ``x`` must be treated as if it has shape ``(1,1,4,2)``). + + Returns + ------- + out: array + a tiled output array. The returned array must have the same data type as ``x`` and must have a rank (i.e., number of dimensions) equal to ``max(N, M)``. If ``S`` is the shape of the tiled array after prepending singleton dimensions (if necessary) and ``r`` is the tuple of repetitions after prepending ones (if necessary), then the number of elements along each axis (dimension) must satisfy ``S[i]*r[i]``, where ``i`` refers to the ``i`` th axis (dimension). + + Notes + ----- + + .. versionadded:: 2023.12 + """ + + +def unstack(x: array, /, *, axis: int = 0) -> Tuple[array, ...]: + """ + Splits an array into a sequence of arrays along the given axis. + + Parameters + ---------- + x: array + input array. + axis: int + axis along which the array will be split. A valid ``axis`` must be on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If provided an ``axis`` outside of the required interval, the function must raise an exception. Default: ``0``. + + Returns + ------- + out: Tuple[array, ...] + tuple of slices along the given dimension. All the arrays have the same shape. + + Notes + ----- + + .. versionadded:: 2023.12 + """ diff --git a/src/array_api_stubs/_2024_12/searching_functions.py b/src/array_api_stubs/_2024_12/searching_functions.py new file mode 100644 index 000000000..2478cda11 --- /dev/null +++ b/src/array_api_stubs/_2024_12/searching_functions.py @@ -0,0 +1,207 @@ +__all__ = ["argmax", "argmin", "count_nonzero", "nonzero", "searchsorted", "where"] + + +from ._types import Optional, Tuple, Literal, Union, array + + +def argmax(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the maximum values along a specified axis. + + When the maximum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the maximum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the maximum value; otherwise, a non-zero-dimensional array containing the indices of the maximum values. The returned array must have be the default array index data type. + """ + + +def argmin(x: array, /, *, axis: Optional[int] = None, keepdims: bool = False) -> array: + """ + Returns the indices of the minimum values along a specified axis. + + When the minimum value occurs multiple times, only the indices corresponding to the first occurrence are returned. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[int] + axis along which to search. If ``None``, the function must return the index of the minimum value of the flattened array. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if ``axis`` is ``None``, a zero-dimensional array containing the index of the first occurrence of the minimum value; otherwise, a non-zero-dimensional array containing the indices of the minimum values. The returned array must have the default array index data type. + """ + + +def count_nonzero( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Counts the number of array elements which are non-zero. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to count non-zero values. By default, the number of non-zero values must be computed over the entire array. If a tuple of integers, the number of non-zero values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the number of non-zeros values was computed over the entire array, a zero-dimensional array containing the total number of non-zero values; otherwise, a non-zero-dimensional array containing the counts along the specified axes. The returned array must have the default array index data type. + + Notes + ----- + + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. versionadded:: 2024.12 + """ + + +def nonzero(x: array, /) -> Tuple[array, ...]: + """ + Returns the indices of the array elements which are non-zero. + + .. admonition:: Data-dependent output shape + :class: admonition important + + The shape of the output array for this function depends on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + Parameters + ---------- + x: array + input array. Must have a positive rank. If ``x`` is zero-dimensional, the function must raise an exception. + + Returns + ------- + out: Tuple[array, ...] + a tuple of ``k`` arrays, one for each dimension of ``x`` and each of size ``n`` (where ``n`` is the total number of non-zero elements), containing the indices of the non-zero elements in that dimension. The indices must be returned in row-major, C-style order. The returned array must have the default array index data type. + + Notes + ----- + + - If ``x`` has a complex floating-point data type, non-zero elements are those elements having at least one component (real or imaginary) which is non-zero. + - If ``x`` has a boolean data type, non-zero elements are those elements which are equal to ``True``. + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def searchsorted( + x1: array, + x2: array, + /, + *, + side: Literal["left", "right"] = "left", + sorter: Optional[array] = None, +) -> array: + """ + Finds the indices into ``x1`` such that, if the corresponding elements in ``x2`` were inserted before the indices, the order of ``x1``, when sorted in ascending order, would be preserved. + + Parameters + ---------- + x1: array + input array. Must be a one-dimensional array. Should have a real-valued data type. If ``sorter`` is ``None``, must be sorted in ascending order; otherwise, ``sorter`` must be an array of indices that sort ``x1`` in ascending order. + x2: array + array containing search values. Should have a real-valued data type. + side: Literal['left', 'right'] + argument controlling which index is returned if a value lands exactly on an edge. + + Let ``v`` be an element of ``x2`` given by ``v = x2[j]``, where ``j`` refers to a valid index (see :ref:`indexing`). + + - If ``v`` is less than all elements in ``x1``, then ``out[j]`` must be ``0``. + - If ``v`` is greater than all elements in ``x1``, then ``out[j]`` must be ``M``, where ``M`` is the number of elements in ``x1``. + - Otherwise, each returned index ``i = out[j]`` must satisfy an index condition: + + - If ``side == 'left'``, then ``x1[i-1] < v <= x1[i]``. + - If ``side == 'right'``, then ``x1[i-1] <= v < x1[i]``. + + Default: ``'left'``. + sorter: Optional[array] + array of indices that sort ``x1`` in ascending order. The array must have the same shape as ``x1`` and have an integer data type. Default: ``None``. + + Returns + ------- + out: array + an array of indices with the same shape as ``x2``. The returned array must have the default array index data type. + + Notes + ----- + + For real-valued floating-point arrays, the sort order of NaNs and signed zeros is unspecified and thus implementation-dependent. Accordingly, when a real-valued floating-point array contains NaNs and signed zeros, what constitutes ascending order may vary among specification-conforming array libraries. + + While behavior for arrays containing NaNs and signed zeros is implementation-dependent, specification-conforming libraries should, however, ensure consistency with ``sort`` and ``argsort`` (i.e., if a value in ``x2`` is inserted into ``x1`` according to the corresponding index in the output array and ``sort`` is invoked on the resultant array, the sorted result should be an array in the same order). + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Fixed incorrect boundary conditions. + """ + + +def where( + condition: array, + x1: Union[array, int, float, complex, bool], + x2: Union[array, int, float, complex, bool], + /, +) -> array: + """ + Returns elements chosen from ``x1`` or ``x2`` depending on ``condition``. + + Parameters + ---------- + condition: array + when ``True``, yield ``x1_i``; otherwise, yield ``x2_i``. Should have a boolean data type. Must be compatible with ``x1`` and ``x2`` (see :ref:`broadcasting`). + x1: Union[array, int, float, complex, bool] + first input array. Must be compatible with ``condition`` and ``x2`` (see :ref:`broadcasting`). + x2: Union[array, int, float, complex, bool] + second input array. Must be compatible with ``condition`` and ``x1`` (see :ref:`broadcasting`). + + Returns + ------- + out: array + an array with elements from ``x1`` where ``condition`` is ``True``, and elements from ``x2`` elsewhere. The returned array must have a data type determined by :ref:`type-promotion` rules with the arrays ``x1`` and ``x2``. + + Notes + ----- + + - At least one of ``x1`` and ``x2`` must be an array. + - If either ``x1`` or ``x2`` is a scalar value, the returned array must have a data type determined according to :ref:`mixing-scalars-and-arrays`. + + .. versionchanged:: 2024.12 + Added scalar argument support. + + .. versionchanged:: 2024.12 + Clarified that the ``condition`` argument should have a boolean data type. + """ diff --git a/src/array_api_stubs/_2024_12/set_functions.py b/src/array_api_stubs/_2024_12/set_functions.py new file mode 100644 index 000000000..5b7e9a56c --- /dev/null +++ b/src/array_api_stubs/_2024_12/set_functions.py @@ -0,0 +1,183 @@ +__all__ = ["unique_all", "unique_counts", "unique_inverse", "unique_values"] + + +from ._types import Tuple, array + + +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``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array, array, array] + a namedtuple ``(values, indices, inverse_indices, counts)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``indices`` and must be an array containing the indices (first occurrences) of a flattened ``x`` that result in ``values``. The array must have the same shape as ``values`` and must have the default array index data type. + - third element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and must have the default array index data type. + - fourth element must have the field name ``counts`` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_counts(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the corresponding counts for each unique element in ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Each ``nan`` value and each complex floating-point value having a ``nan`` component should have a count of one, while the counts for signed zeros should be aggregated as a single count. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple `(values, counts)` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name `counts` and must be an array containing the number of times each unique element occurs in ``x``. The order of the returned counts must match the order of ``values``, such that a specific element in ``counts`` corresponds to the respective unique element in ``values``. The returned array must have same shape as ``values`` and must have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior and required the order of ``counts`` match the order of ``values``. + """ + + +def unique_inverse(x: array, /) -> Tuple[array, array]: + """ + Returns the unique elements of an input array ``x`` and the indices from the set of unique elements that reconstruct ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + As signed zeros are not distinct, using ``inverse_indices`` to reconstruct the input array is not guaranteed to return an array having the exact same values. + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: Tuple[array, array] + a namedtuple ``(values, inverse_indices)`` whose + + - first element must have the field name ``values`` and must be a one-dimensional array containing the unique elements of ``x``. The array must have the same data type as ``x``. + - second element must have the field name ``inverse_indices`` and must be an array containing the indices of ``values`` that reconstruct ``x``. The array must have the same shape as ``x`` and have the default array index data type. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Clarified flattening behavior. + """ + + +def unique_values(x: array, /) -> array: + """ + Returns the unique elements of an input array ``x``. + + .. admonition:: Data-dependent output shape + :class: important + + The shapes of two of the output arrays for this function depend on the data values in the input array; hence, array libraries which build computation graphs (e.g., JAX, Dask, etc.) may find this function difficult to implement without knowing array values. Accordingly, such libraries may choose to omit this function. See :ref:`data-dependent-output-shapes` section for more details. + + .. note:: + Uniqueness 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``, ``nan`` values should be considered distinct. + - As complex floating-point values having at least one ``nan`` component compare as ``False``, complex floating-point values having ``nan`` components should be considered distinct. + - As ``-0`` and ``+0`` compare as ``True``, signed zeros should not be considered distinct, and the corresponding unique element will be implementation-dependent (e.g., an implementation could choose to return ``-0`` if ``-0`` occurs before ``+0``). + + Parameters + ---------- + x: array + input array. If ``x`` has more than one dimension, the function must flatten ``x`` and return the unique elements of the flattened array. + + Returns + ------- + out: array + a one-dimensional array containing the set of unique elements in ``x``. The returned array must have the same data type as ``x``. + + .. note:: + The order of unique elements is not specified and may vary between implementations. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required that the output array must be one-dimensional. + """ diff --git a/src/array_api_stubs/_2024_12/sorting_functions.py b/src/array_api_stubs/_2024_12/sorting_functions.py new file mode 100644 index 000000000..2dc4ac410 --- /dev/null +++ b/src/array_api_stubs/_2024_12/sorting_functions.py @@ -0,0 +1,58 @@ +__all__ = ["argsort", "sort"] + + +from ._types import array + + +def argsort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns the indices that sort an array ``x`` along a specified axis. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x : array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the returned indices sort ``x`` in descending order (by value). If ``False``, the returned indices sort ``x`` in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned indices must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned indices may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + an array of indices. The returned array must have the same shape as ``x``. The returned array must have the default array index data type. + """ + + +def sort( + x: array, /, *, axis: int = -1, descending: bool = False, stable: bool = True +) -> array: + """ + Returns a sorted copy of an input array ``x``. + + .. note:: + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-dependent (see :ref:`complex-number-ordering`). + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: int + axis along which to sort. If set to ``-1``, the function must sort along the last axis. Default: ``-1``. + descending: bool + sort order. If ``True``, the array must be sorted in descending order (by value). If ``False``, the array must be sorted in ascending order (by value). Default: ``False``. + stable: bool + sort stability. If ``True``, the returned array must maintain the relative order of ``x`` values which compare as equal. If ``False``, the returned array may or may not maintain the relative order of ``x`` values which compare as equal (i.e., the relative order of ``x`` values which compare as equal is implementation-dependent). Default: ``True``. + + Returns + ------- + out : array + a sorted array. The returned array must have the same data type and shape as ``x``. + """ diff --git a/src/array_api_stubs/_2024_12/statistical_functions.py b/src/array_api_stubs/_2024_12/statistical_functions.py new file mode 100644 index 000000000..d318f6d2a --- /dev/null +++ b/src/array_api_stubs/_2024_12/statistical_functions.py @@ -0,0 +1,455 @@ +__all__ = [ + "cumulative_sum", + "cumulative_prod", + "max", + "mean", + "min", + "prod", + "std", + "sum", + "var", +] + + +from ._types import Optional, Tuple, Union, array, dtype + + +def cumulative_prod( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative product of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative product must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative product 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. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the product (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the multiplicative identity (i.e., one). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative product. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative product must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionadded:: 2024.12 + """ + + +def cumulative_sum( + x: array, + /, + *, + axis: Optional[int] = None, + dtype: Optional[dtype] = None, + include_initial: bool = False, +) -> array: + """ + Calculates the cumulative sum of elements in the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have one or more dimensions (axes). Should have a numeric data type. + axis: Optional[int] + axis along which a cumulative sum must be computed. If ``axis`` is negative, the function must determine the axis along which to compute a cumulative sum 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. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + include_initial: bool + boolean indicating whether to include the initial value as the first value in the output. By convention, the initial value must be the additive identity (i.e., zero). Default: ``False``. + + Returns + ------- + out: array + an array containing the cumulative sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Let ``N`` be the size of the axis along which to compute the cumulative sum. The returned array must have a shape determined according to the following rules: + + - if ``include_initial`` is ``True``, the returned array must have the same shape as ``x``, except the size of the axis along which to compute the cumulative sum must be ``N+1``. + - if ``include_initial`` is ``False``, the returned array must have the same shape as ``x``. + + Notes + ----- + + - When ``x`` is a zero-dimensional array, behavior is unspecified and thus implementation-defined. + + **Special Cases** + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionadded:: 2023.12 + + .. versionchanged:: 2024.12 + Behavior when providing a zero-dimensional array is explicitly left unspecified. + """ + + +def max( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the maximum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which maximum values must be computed. By default, the maximum value must be computed over the entire array. If a tuple of integers, maximum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the maximum value was computed over the entire array, a zero-dimensional array containing the maximum value; otherwise, a non-zero-dimensional array containing the maximum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the maximum value is zero, the maximum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the minimum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``-infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a maximum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the maximum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def mean( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the arithmetic mean of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which arithmetic means must be computed. By default, the mean must be computed over the entire array. If a tuple of integers, arithmetic means must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the arithmetic mean was computed over the entire array, a zero-dimensional array containing the arithmetic mean; otherwise, a non-zero-dimensional array containing the arithmetic means. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the arithmetic mean. For real-valued operands, + + - If ``N`` is ``0``, the arithmetic mean is ``NaN``. + - If ``x_i`` is ``NaN``, the arithmetic mean is ``NaN`` (i.e., ``NaN`` values propagate). + + For complex floating-point operands, real-valued floating-point special cases should independently apply to the real and imaginary component operations involving real numbers. For example, let ``a = real(x_i)`` and ``b = imag(x_i)``, and + + - If ``N`` is ``0``, the arithmetic mean is ``NaN + NaN j``. + - If ``a`` is ``NaN``, the real component of the result is ``NaN``. + - Similarly, if ``b`` is ``NaN``, the imaginary component of the result is ``NaN``. + + .. note:: + Array libraries, such as NumPy, PyTorch, and JAX, currently deviate from this specification in their handling of components which are ``NaN`` when computing the arithmetic mean. In general, consumers of array libraries implementing this specification should use :func:`~array_api.isnan` to test whether the result of computing the arithmetic mean over an array have a complex floating-point data type is ``NaN``, rather than relying on ``NaN`` propagation of individual components. + + .. versionchanged:: 2024.12 + Added complex data type support. + """ + + +def min( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the minimum value of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which minimum values must be computed. By default, the minimum value must be computed over the entire array. If a tuple of integers, minimum values must be computed over multiple axes. Default: ``None``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the minimum value was computed over the entire array, a zero-dimensional array containing the minimum value; otherwise, a non-zero-dimensional array containing the minimum values. The returned array must have the same data type as ``x``. + + Notes + ----- + + When the number of elements over which to compute the minimum value is zero, the minimum value is implementation-defined. Specification-compliant libraries may choose to raise an error, return a sentinel value (e.g., if ``x`` is a floating-point input array, return ``NaN``), or return the maximum possible value for the input array ``x`` data type (e.g., if ``x`` is a floating-point array, return ``+infinity``). + + The order of signed zeros is unspecified and thus implementation-defined. When choosing between ``-0`` or ``+0`` as a minimum value, specification-compliant libraries may choose to return either value. + + For backward compatibility, conforming implementations may support complex numbers; however, inequality comparison of complex numbers is unspecified and thus implementation-defined (see :ref:`complex-number-ordering`). + + **Special Cases** + + For floating-point operands, + + - If ``x_i`` is ``NaN``, the minimum value is ``NaN`` (i.e., ``NaN`` values propagate). + + .. versionchanged:: 2023.12 + Clarified that the order of signed zeros is implementation-defined. + """ + + +def prod( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the product of input array ``x`` elements. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which products must be computed. By default, the product must be computed over the entire array. If a tuple of integers, products must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the product was computed over the entire array, a zero-dimensional array containing the product; otherwise, a non-zero-dimensional array containing the products. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the product. + + - If ``N`` is ``0``, the product is `1` (i.e., the empty product). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.multiply`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def std( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the standard deviation of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which standard deviations must be computed. By default, the standard deviation must be computed over the entire array. If a tuple of integers, standard deviations must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the standard deviation according to ``N-c`` where ``N`` corresponds to the total number of elements over which the standard deviation is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the standard deviation of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the corrected sample standard deviation, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the standard deviation was computed over the entire array, a zero-dimensional array containing the standard deviation; otherwise, a non-zero-dimensional array containing the standard deviations. The returned array must have the same data type as ``x``. + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the standard deviation. + + - If ``N - correction`` is less than or equal to ``0``, the standard deviation is ``NaN``. + - If ``x_i`` is ``NaN``, the standard deviation is ``NaN`` (i.e., ``NaN`` values propagate). + """ + + +def sum( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + dtype: Optional[dtype] = None, + keepdims: bool = False, +) -> array: + """ + Calculates the sum of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which sums must be computed. By default, the sum must be computed over the entire array. If a tuple of integers, sums must be computed over multiple axes. Default: ``None``. + + dtype: Optional[dtype] + data type of the returned array. If ``None``, the returned array must have the same data type as ``x``, unless ``x`` has an integer data type supporting a smaller range of values than the default integer data type (e.g., ``x`` has an ``int16`` or ``uint32`` data type and the default integer data type is ``int64``). In those latter cases: + + - if ``x`` has a signed integer data type (e.g., ``int16``), the returned array must have the default integer data type. + - if ``x`` has an unsigned integer data type (e.g., ``uint16``), the returned array must have an unsigned integer data type having the same number of bits as the default integer data type (e.g., if the default integer data type is ``int32``, the returned array must have a ``uint32`` data type). + + If the data type (either specified or resolved) differs from the data type of ``x``, the input array should be cast to the specified data type before computing the sum (rationale: the ``dtype`` keyword argument is intended to help prevent overflows). Default: ``None``. + + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the sum was computed over the entire array, a zero-dimensional array containing the sum; otherwise, an array containing the sums. The returned array must have a data type as described by the ``dtype`` parameter above. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the sum. + + - If ``N`` is ``0``, the sum is ``0`` (i.e., the empty sum). + + For both real-valued and complex floating-point operands, special cases must be handled as if the operation is implemented by successive application of :func:`~array_api.add`. + + .. versionchanged:: 2022.12 + Added complex data type support. + + .. versionchanged:: 2023.12 + Required the function to return a floating-point array having the same data type as the input array when provided a floating-point array. + """ + + +def var( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + correction: Union[int, float] = 0.0, + keepdims: bool = False, +) -> array: + """ + Calculates the variance of the input array ``x``. + + Parameters + ---------- + x: array + input array. Should have a real-valued floating-point data type. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which variances must be computed. By default, the variance must be computed over the entire array. If a tuple of integers, variances must be computed over multiple axes. Default: ``None``. + correction: Union[int, float] + degrees of freedom adjustment. Setting this parameter to a value other than ``0`` has the effect of adjusting the divisor during the calculation of the variance according to ``N-c`` where ``N`` corresponds to the total number of elements over which the variance is computed and ``c`` corresponds to the provided degrees of freedom adjustment. When computing the variance of a population, setting this parameter to ``0`` is the standard choice (i.e., the provided array contains data constituting an entire population). When computing the unbiased sample variance, setting this parameter to ``1`` is the standard choice (i.e., the provided array contains data sampled from a larger population; this is commonly referred to as Bessel's correction). Default: ``0``. + keepdims: bool + if ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if the variance was computed over the entire array, a zero-dimensional array containing the variance; otherwise, a non-zero-dimensional array containing the variances. The returned array must have the same data type as ``x``. + + + .. note:: + While this specification recommends that this function only accept input arrays having a real-valued floating-point data type, specification-compliant array libraries may choose to accept input arrays having an integer data type. While mixed data type promotion is implementation-defined, if the input array ``x`` has an integer data type, the returned array must have the default real-valued floating-point data type. + + Notes + ----- + + **Special Cases** + + Let ``N`` equal the number of elements over which to compute the variance. + + - If ``N - correction`` is less than or equal to ``0``, the variance is ``NaN``. + - If ``x_i`` is ``NaN``, the variance is ``NaN`` (i.e., ``NaN`` values propagate). + """ diff --git a/src/array_api_stubs/_2024_12/utility_functions.py b/src/array_api_stubs/_2024_12/utility_functions.py new file mode 100644 index 000000000..539833356 --- /dev/null +++ b/src/array_api_stubs/_2024_12/utility_functions.py @@ -0,0 +1,131 @@ +__all__ = ["all", "any", "diff"] + + +from ._types import Optional, Tuple, Union, array + + +def all( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether all input array elements evaluate to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``True``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical AND reduction. By default, a logical AND reduction must be performed over the entire array. If a tuple of integers, logical AND reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical AND reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def any( + x: array, + /, + *, + axis: Optional[Union[int, Tuple[int, ...]]] = None, + keepdims: bool = False, +) -> array: + """ + Tests whether any input array element evaluates to ``True`` along a specified axis. + + .. note:: + Positive infinity, negative infinity, and NaN must evaluate to ``True``. + + .. note:: + If ``x`` has a complex floating-point data type, elements having a non-zero component (real or imaginary) must evaluate to ``True``. + + .. note:: + If ``x`` is an empty array or the size of the axis (dimension) along which to evaluate elements is zero, the test result must be ``False``. + + Parameters + ---------- + x: array + input array. + axis: Optional[Union[int, Tuple[int, ...]]] + axis or axes along which to perform a logical OR reduction. By default, a logical OR reduction must be performed over the entire array. If a tuple of integers, logical OR reductions must be performed over multiple axes. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to perform a reduction by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``None``. + keepdims: bool + If ``True``, the reduced axes (dimensions) must be included in the result as singleton dimensions, and, accordingly, the result must be compatible with the input array (see :ref:`broadcasting`). Otherwise, if ``False``, the reduced axes (dimensions) must not be included in the result. Default: ``False``. + + Returns + ------- + out: array + if a logical OR reduction was performed over the entire array, the returned array must be a zero-dimensional array containing the test result; otherwise, the returned array must be a non-zero-dimensional array containing the test results. The returned array must have a data type of ``bool``. + + Notes + ----- + + .. versionchanged:: 2022.12 + Added complex data type support. + """ + + +def diff( + x: array, + /, + *, + axis: int = -1, + n: int = 1, + prepend: Optional[array] = None, + append: Optional[array] = None, +) -> array: + """ + Calculates the n-th discrete forward difference along a specified axis. + + Parameters + ---------- + x: array + input array. Should have a numeric data type. + axis: int + axis along which to compute differences. A valid ``axis`` must be an integer on the interval ``[-N, N)``, where ``N`` is the rank (number of dimensions) of ``x``. If an ``axis`` is specified as a negative integer, the function must determine the axis along which to compute differences by counting backward from the last dimension (where ``-1`` refers to the last dimension). If provided an invalid ``axis``, the function must raise an exception. Default: ``-1``. + n: int + number of times to recursively compute differences. Default: ``1``. + prepend: Optional[array] + values to prepend to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + append: Optional[array] + values to append to a specified axis prior to computing differences. Must have the same shape as ``x``, except for the axis specified by ``axis`` which may have any size. Should have the same data type as ``x``. Default: ``None``. + + Returns + ------- + out: array + an array containing the n-th differences. Should have the same data type as ``x``. Must have the same shape as ``x``, except for the axis specified by ``axis`` which must have a size determined as follows: + + - Let ``M`` be the number of elements along an axis specified by ``axis``. + - Let ``N1`` be the number of prepended values along an axis specified by ``axis``. + - Let ``N2`` be the number of appended values along an axis specified by ``axis``. + - The final size of the axis specified by ``axis`` must be ``M + N1 + N2 - n``. + + Notes + ----- + + - The first-order differences are given by ``out[i] = x[i+1] - x[i]`` along a specified axis. Higher-order differences must be calculated recursively (e.g., by calling ``diff(out, axis=axis, n=n-1)``). + - If a conforming implementation chooses to support ``prepend`` and ``append`` arrays which have a different data type than ``x``, behavior is unspecified and thus implementation-defined. Implementations may choose to type promote (:ref:`type-promotion`), cast ``prepend`` and/or ``append`` to the same data type as ``x``, or raise an exception. + + .. versionadded:: 2024.12 + """ diff --git a/src/array_api_stubs/__init__.py b/src/array_api_stubs/__init__.py index ca9122e7f..beb6809b8 100644 --- a/src/array_api_stubs/__init__.py +++ b/src/array_api_stubs/__init__.py @@ -1 +1 @@ -from . import _2021_12, _2022_12, _2023_12, _draft +from . import _2021_12, _2022_12, _2023_12, _2024_12, _draft From 772fb461da6ff904ecfcac4a24676e40efcbdb0c Mon Sep 17 00:00:00 2001 From: Athan Date: Wed, 26 Feb 2025 17:17:40 -0800 Subject: [PATCH 550/551] docs: fix changelog links PR-URL: https://github.com/data-apis/array-api/pull/908 Reviewed-by: Athan Reines --- CHANGELOG.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0919472d9..ca883c3b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -135,18 +135,18 @@ The following is a list of breaking changes relative to the previous version of The following is a list of fixes and points of clarification with regard to the previous version of the specification: -- `__add__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__add__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `__bool__`: fix typo in special case notes ([gh-785](https://github.com/data-apis/array-api/pull/785)) - `__dlpack__`: resolve conflicting exception guidance ([gh-887](https://github.com/data-apis/array-api/pull/887)) -- `__eq__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__eq__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `__getitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) -- `__mul__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__ne__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__pow__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__mul__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__ne__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__pow__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `__setitem__`: clarify required indexing semantics ([gh-821](https://github.com/data-apis/array-api/pull/821)) -- `__setitem__`: fix typing for `value` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__sub__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) -- `__truediv__`: fix typing for `other` argument ([gh-https://github.com/data-apis/array-api/pull/905](https://github.com/data-apis/array-api/pull/905)) +- `__setitem__`: fix typing for `value` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__sub__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) +- `__truediv__`: fix typing for `other` argument ([gh-905](https://github.com/data-apis/array-api/pull/905)) - `broadcast_to`: clarify broadcast behavior ([gh-888](https://github.com/data-apis/array-api/pull/888)) - `broadcast_to`: clarify required exception behavior ([gh-897](https://github.com/data-apis/array-api/pull/897)) - `clip`: clarify that the operation is only defined when elements in `min` and `max` are inside the bounds of the input array data type ([gh-814](https://github.com/data-apis/array-api/pull/814)) @@ -160,7 +160,7 @@ The following is a list of fixes and points of clarification with regard to the - `fft.irfftn`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) - `fft.hfft`: fix typo in function description ([gh-806](https://github.com/data-apis/array-api/pull/806)) - `linalg.solve`: clarify broadcasting semantics and output shape ([gh-810](https://github.com/data-apis/array-api/pull/810)) -- `nonzero`: fix return type ([gh-803](https://github.com/data-apis/array-api/pull/803) and [gh-https://github.com/data-apis/array-api/pull/904](https://github.com/data-apis/array-api/pull/904)) +- `nonzero`: fix return type ([gh-803](https://github.com/data-apis/array-api/pull/803) and [gh-904](https://github.com/data-apis/array-api/pull/904)) - `searchsorted`: fix incorrect boundary conditions ([gh-898](https://github.com/data-apis/array-api/pull/898)) - `sign`: fix equation in function description ([gh-844](https://github.com/data-apis/array-api/pull/844)) - `tile`: fix missing return type ([gh-798](https://github.com/data-apis/array-api/pull/798)) From 0941b216f6231195f1f6a332f957e45554f5da79 Mon Sep 17 00:00:00 2001 From: Guido Imperiale Date: Thu, 3 Apr 2025 08:10:54 +0100 Subject: [PATCH 551/551] docs: fix `indexing` kwarg typing in `meshgrid` PR-URL: https://github.com/data-apis/array-api/pull/915 Reviewed-by: Athan Reines Reviewed-by: Lucas Colley --- src/array_api_stubs/_2021_12/creation_functions.py | 5 +++-- src/array_api_stubs/_2022_12/creation_functions.py | 5 +++-- src/array_api_stubs/_2023_12/creation_functions.py | 5 +++-- src/array_api_stubs/_2024_12/creation_functions.py | 5 +++-- src/array_api_stubs/_draft/creation_functions.py | 5 +++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/array_api_stubs/_2021_12/creation_functions.py b/src/array_api_stubs/_2021_12/creation_functions.py index c7659d0df..6942459ee 100644 --- a/src/array_api_stubs/_2021_12/creation_functions.py +++ b/src/array_api_stubs/_2021_12/creation_functions.py @@ -1,5 +1,6 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -311,7 +312,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -319,7 +320,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_2022_12/creation_functions.py b/src/array_api_stubs/_2022_12/creation_functions.py index 42d6f9420..88fd6159f 100644 --- a/src/array_api_stubs/_2022_12/creation_functions.py +++ b/src/array_api_stubs/_2022_12/creation_functions.py @@ -1,5 +1,6 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -372,7 +373,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -380,7 +381,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_2023_12/creation_functions.py b/src/array_api_stubs/_2023_12/creation_functions.py index 6de79268e..66c3e1d6b 100644 --- a/src/array_api_stubs/_2023_12/creation_functions.py +++ b/src/array_api_stubs/_2023_12/creation_functions.py @@ -20,6 +20,7 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -454,7 +455,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -462,7 +463,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_2024_12/creation_functions.py b/src/array_api_stubs/_2024_12/creation_functions.py index c09800783..bfe690cd6 100644 --- a/src/array_api_stubs/_2024_12/creation_functions.py +++ b/src/array_api_stubs/_2024_12/creation_functions.py @@ -20,6 +20,7 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -454,7 +455,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -462,7 +463,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns diff --git a/src/array_api_stubs/_draft/creation_functions.py b/src/array_api_stubs/_draft/creation_functions.py index c09800783..bfe690cd6 100644 --- a/src/array_api_stubs/_draft/creation_functions.py +++ b/src/array_api_stubs/_draft/creation_functions.py @@ -20,6 +20,7 @@ from ._types import ( List, + Literal, NestedSequence, Optional, SupportsBufferProtocol, @@ -454,7 +455,7 @@ def linspace( """ -def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: +def meshgrid(*arrays: array, indexing: Literal["xy", "ij"] = "xy") -> List[array]: """ Returns coordinate matrices from coordinate vectors. @@ -462,7 +463,7 @@ def meshgrid(*arrays: array, indexing: str = "xy") -> List[array]: ---------- arrays: array an arbitrary number of one-dimensional arrays representing grid coordinates. Each array should have the same numeric data type. - indexing: str + indexing: Literal["xy", "ij"] Cartesian ``'xy'`` or matrix ``'ij'`` indexing of output. If provided zero or one one-dimensional vector(s) (i.e., the zero- and one-dimensional cases, respectively), the ``indexing`` keyword has no effect and should be ignored. Default: ``'xy'``. Returns