From f20cedafd5d794e3861ce6bf8532116a04462856 Mon Sep 17 00:00:00 2001 From: ajz34 Date: Tue, 24 Feb 2026 14:51:25 +0800 Subject: [PATCH 1/5] update array api fullfillment --- rstsr-core/src/device_faer/device.rs | 2 +- rstsr-core/src/docs/array_api_standard.md | 417 ++++++++++++---------- 2 files changed, 235 insertions(+), 184 deletions(-) diff --git a/rstsr-core/src/device_faer/device.rs b/rstsr-core/src/device_faer/device.rs index d15fdc6..e85427b 100644 --- a/rstsr-core/src/device_faer/device.rs +++ b/rstsr-core/src/device_faer/device.rs @@ -7,7 +7,7 @@ pub struct DeviceFaer { base: DeviceCpuRayon, } -pub(crate) use DeviceFaer as DeviceRayonAutoImpl; +pub(crate) use self::DeviceFaer as DeviceRayonAutoImpl; impl DeviceFaer { pub fn new(num_threads: usize) -> Self { diff --git a/rstsr-core/src/docs/array_api_standard.md b/rstsr-core/src/docs/array_api_standard.md index 91da536..3541c5d 100644 --- a/rstsr-core/src/docs/array_api_standard.md +++ b/rstsr-core/src/docs/array_api_standard.md @@ -13,15 +13,15 @@ For column status: | status | implementation | Python API | description | |-|-|-|-| -| D | | `__pos__` | `+x` | -| Y | `-` | `__neg__` | `-x` | -| Y | `+` | `__add__` | `x1 + x2` | -| Y | `-` | `__sub__` | `x1 - x2` | -| Y | `*` | `__mul__` | `x1 * x2` | -| Y | `/` | `__truediv__` | `x1 / x2` | -| Y | `floor_divide` | `__floordiv__` | `x1 // x2` | -| **C** | [`rt::rem`][^2] | `__mod__` | `x1 % x2` | -| Y | [`pow`] | `__pow__` | `x1 ** x2` | +| D | | [`__pos__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__pos__.html) | `+x` | +| Y | `-` | [`__neg__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__neg__.html) | `-x` | +| Y | `+` | [`__add__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__add__.html) | `x1 + x2` | +| Y | `-` | [`__sub__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__sub__.html) | `x1 - x2` | +| Y | `*` | [`__mul__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__mul__.html) | `x1 * x2` | +| Y | `/` | [`__truediv__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__truediv__.html) | `x1 / x2` | +| Y | `floor_divide` | [`__floordiv__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__floordiv__.html) | `x1 // x2` | +| **C** | [`rt::rem`][^2] | [`__mod__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__mod__.html) | `x1 % x2` | +| Y | [`pow`] | [`__pow__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__pow__.html) | `x1 ** x2` | | Y | `+=` | `__iadd__` | `x1 += x2` | | Y | `-=` | `__isub__` | `x1 -= x2` | | Y | `*=` | `__imul__` | `x1 *= x2` | @@ -35,7 +35,6 @@ For column status: **Changed feature** - `__mod__`: We do not use remainder function to represent something like `8 % 3 = 2`, but instead using notation `%` to represent matrix multiplication (`@` in python/numpy). - **Dropped support** - `__pos__`: In rust, leading `+` is not allowed. - `__ifloordiv__`: This is not a priority for implementation. @@ -45,25 +44,25 @@ For column status: | status | implementation | Python API | description | |-|-|-|-| -| **C** | `%`, [`matmul()`] | `__matmul__` | `x1 @ x2` | +| **C** | `%`, [`matmul()`] | [`__matmul__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__matmul__.html) | `x1 @ x2` | | D | | `__imatmul__` | `x1 @= x2` | **Changed feature** - `__matmul__`: In rust, there was discussions whether to implement `@` as matrix multiplication (or other operator notations, since `@` has been used in binary operation for pattern matching). Instead we use notation `%` to represent matrix multiplication (`@` in python/numpy). See `__rem__` function for more information. -Dropped support +**Dropped support** - `__imatmul__`: Inplace matmul is not convenient to be realized. ### Bitwise Operators | status | implementation | Python API | description | |-|-|-|-| -| Y | `!` [`Not`] | `__invert__` | `~x` | -| Y | `&` [`BitAnd`] | `__and__` | `x1 & x2` | -| Y | `\|` [`BitOr`] | `__or__` | `x1 \| x2` | -| Y | `^` [`BitXor`] | `__xor__` | `x1 ^ x2` | -| Y | `<<` [`Shl`] | `__lshift__` | `x1 << x2` | -| Y | `>>` [`Shr`] | `__rshift__` | `x1 >> x2` | +| Y | `!` [`Not`] | [`__invert__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__invert__.html) | `~x` | +| Y | `&` [`BitAnd`] | [`__and__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__and__.html) | `x1 & x2` | +| Y | `\|` [`BitOr`] | [`__or__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__or__.html) | `x1 \| x2` | +| Y | `^` [`BitXor`] | [`__xor__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__xor__.html) | `x1 ^ x2` | +| Y | `<<` [`Shl`] | [`__lshift__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__lshift__.html) | `x1 << x2` | +| Y | `>>` [`Shr`] | [`__rshift__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__rshift__.html) | `x1 >> x2` | | Y | `&=` [`BitAndAssign`] | `__iand__` | `x1 &= x2` | | Y | `\|=` [`BitOrAssign`] | `__ior__` | `x1 \|= x2` | | Y | `^=` [`BitXorAssign`] | `__ixor__` | `x1 ^= x2` | @@ -74,68 +73,69 @@ Dropped support | status | implementation | Python API | description | |-|-|-|-| -| Y | [`lt`], [`less`] | `__lt__` | `x1 < x2` | -| Y | [`le`], [`less_equal`] | `__le__` | `x1 <= x2` | -| Y | [`gt`], [`greater`] | `__gt__` | `x1 > x2` | -| Y | [`ge`], [`greater_equal`] | `__ge__` | `x1 >= x2` | -| Y | [`eq`], [`equal`] | `__eq__` | `x1 == x2` | -| Y | [`ne`], [`not_equal`] | `__ne__` | `x1 != x2` | +| Y | [`lt`], [`less`] | [`__lt__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__lt__.html) | `x1 < x2` | +| Y | [`le`], [`less_equal`] | [`__le__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__le__.html) | `x1 <= x2` | +| Y | [`gt`], [`greater`] | [`__gt__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__gt__.html) | `x1 > x2` | +| Y | [`ge`], [`greater_equal`] | [`__ge__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__ge__.html) | `x1 >= x2` | +| Y | [`eq`], [`equal`] | [`__eq__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__eq__.html) | `x1 == x2` | +| Y | [`ne`], [`not_equal`] | [`__ne__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__ne__.html) | `x1 != x2` | ### Array Object Attributes | status | implementation | Python API | description | |-|-|-|-| -| C | `T` of [`TensorAny`] | `dtype` | Data type of the array elements. | -| C | `B` of [`TensorAny`] | `device` | Hardware device the array data resides on. | -| Y | [`TensorBase::swapaxes`]`(-1, -2)` | `mT` | Transpose of a matrix (or a stack of matrices). | -| Y | [`TensorBase::ndim`] | `ndim` | Number of array dimensions (axes). | -| Y | [`TensorBase::shape`] | `shape` | Array dimensions. | -| Y | [`TensorBase::size`] | `size` | Number of elements in an array. | -| Y | [`transpose`], [`TensorBase::t`] | `T` | Transpose of the array. | +| C | `T` of [`TensorAny`] | [`dtype`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.dtype.html) | Data type of the array elements. | +| C | `B` of [`TensorAny`] | [`device`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.device.html) | Hardware device the array data resides on. | +| Y | [`TensorBase::swapaxes`]`(-1, -2)` | [`mT`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.mT.html) | Transpose of a matrix (or a stack of matrices). | +| Y | [`TensorBase::ndim`] | [`ndim`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.ndim.html) | Number of array dimensions (axes). | +| Y | [`TensorBase::shape`] | [`shape`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.shape.html) | Array dimensions. | +| Y | [`TensorBase::size`] | [`size`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.size.html) | Number of elements in an array. | +| Y | [`transpose`], [`TensorBase::t`] | [`T`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.T.html) | Transpose of the array. | ### Methods | status | implementation | Python API | description | |-|-|-|-| -| Y | [`abs`] | `__abs__` | Calculates the absolute value for each element of an array instance. | -| Y | [`asarray`] | `__bool__` | Converts a zero-dimensional array to a Python bool object. | -| Y | [`asarray`] | `__complex__` | Converts a zero-dimensional array to a Python `complex` object. | -| Y | [`asarray`] | `__float__` | Converts a zero-dimensional array to a Python `float` object. | -| Y | [`Index`] | `__getitem__` | Returns `self[key]`. | -| Y | [`TensorBase::to_scalar`] | `__index__` | Converts a zero-dimensional integer array to a Python `int` object. | -| Y | [`asarray`] | `__int__` | Converts a zero-dimensional array to a Python `int` object. | -| Y | [`IndexMut`] | `__setitem__` | Sets `self[key]` to `value`. | -| P | [`DeviceChangeAPI::to_device`] | `to_device` | Copy the array from the device on which it currently resides to the specified `device`. | +| Y | [`abs`] | [`__abs__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__abs__.html) | Calculates the absolute value for each element of an array instance. | +| Y | [`asarray`] | [`__bool__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__bool__.html) | Converts a zero-dimensional array to a Python bool object. | +| Y | [`asarray`] | [`__complex__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__complex__.html) | Converts a zero-dimensional array to a Python `complex` object. | +| Y | [`asarray`] | [`__float__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__float__.html) | Converts a zero-dimensional array to a Python `float` object. | +| Y | [`Index`] | [`__getitem__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__getitem__.html) | Returns `self[key]`. | +| Y | [`TensorBase::to_scalar`] | [`__index__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__index__.html) | Converts a zero-dimensional integer array to a Python `int` object. | +| Y | [`asarray`] | [`__int__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__int__.html) | Converts a zero-dimensional array to a Python `int` object. | +| Y | [`IndexMut`] | [`__setitem__`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.__setitem__.html) | Sets `self[key]` to `value`. | +| P | [`DeviceChangeAPI::to_device`] | [`to_device`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.array.to_device.html) | Copy the array from the device on which it currently resides to the specified `device`. | ## Constants | status | implementation | Python API | description | |-|-|-|-| -| Y | [`core::f64::consts::E`] | [`e`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.constants.e.html) | IEEE 754 floating-point representation of Euler's constant. | -| Y | [`f64::INFINITY`] | [`inf`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.constants.inf.html) | IEEE 754 floating-point representation of (positive) infinity. | -| Y | [`f64::NAN`] | [`nan`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.constants.nan.html) | IEEE 754 floating-point representation of Not a Number (NaN). | -| Y | [`Indexer::Insert`] | [`newaxis`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.constants.newaxis.html) | An alias for None which is useful for indexing arrays. | -| Y | [`core::f64::consts::PI`] | [`pi`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.constants.pi.html) | IEEE 754 floating-point representation of the mathematical constant π. | +| Y | [`core::f64::consts::E`] | [`e`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.constants.e.html) | IEEE 754 floating-point representation of Euler's constant. | +| Y | [`f64::INFINITY`] | [`inf`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.constants.inf.html) | IEEE 754 floating-point representation of (positive) infinity. | +| Y | [`f64::NAN`] | [`nan`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.constants.nan.html) | IEEE 754 floating-point representation of Not a Number (NaN). | +| Y | [`Indexer::Insert`] | [`newaxis`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.constants.newaxis.html) | An alias for None which is useful for indexing arrays. | +| Y | [`core::f64::consts::PI`] | [`pi`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.constants.pi.html) | IEEE 754 floating-point representation of the mathematical constant π. | ## Creation Functions | status | implementation | Python API | description | |-|-|-|-| -| Y | [`arange`] | [`arange`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.empty.html) | Returns evenly spaced values within the half-open interval `[start, stop)` as a one-dimensional array. | -| P | [`asarray`] | [`asarray`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.asarray.html) | Convert the input to an array. | -| Y | [`empty`] | [`empty`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.empty.html) | Returns an uninitialized array having a specified `shape`. | -| Y | [`empty_like`] | [`empty_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.empty_like.html) | Returns an uninitialized array with the same `shape` as an input array `x`. | -| Y | [`eye`] | [`eye`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.eye.html) | Returns a two-dimensional array with ones on the kth diagonal and zeros elsewhere. | -| Y | [`full`] | [`full`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.full.html) | Returns a new array having a specified `shape` and filled with `fill_value`. | -| Y | [`full_like`] | [`full_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.full_like.html) | Returns a new array filled with fill_value and having the same `shape` as an input array `x`. | -| Y | [`linspace`] | [`linspace`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.linspace.html) | Returns evenly spaced numbers over a specified interval. | -| Y | [`meshgrid`] | `meshgrid` | Returns coordinate matrices from coordinate vectors. | -| Y | [`ones`] | [`ones`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.ones.html) | Returns a new array having a specified shape and filled with ones. | -| Y | [`ones_like`] | [`ones_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.ones_like.html) | Returns a new array filled with ones and having the same `shape` as an input array `x`. | -| Y | [`tril`] | `tril` | Returns the lower triangular part of a matrix (or a stack of matrices) `x`. | -| Y | [`triu`] | `triu` | Returns the upper triangular part of a matrix (or a stack of matrices) `x`. | -| Y | [`zeros`] | [`zeros`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.zeros.html) | Returns a new array having a specified `shape` and filled with zeros. | -| Y | [`zeros_like`] | [`zeros_like`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.zeros_like.html) | Returns a new array filled with zeros and having the same `shape` as an input array x. | +| Y | [`arange`] | [`arange`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.arange.html) | Returns evenly spaced values within the half-open interval `[start, stop)` as a one-dimensional array. | +| P | [`asarray`] | [`asarray`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.asarray.html) | Convert the input to an array. | +| Y | [`empty`] | [`empty`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.empty.html) | Returns an uninitialized array having a specified `shape`. | +| Y | [`empty_like`] | [`empty_like`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.empty_like.html) | Returns an uninitialized array with the same `shape` as an input array `x`. | +| Y | [`eye`] | [`eye`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.eye.html) | Returns a two-dimensional array with ones on the kth diagonal and zeros elsewhere. | +| D | | [`from_dlpack`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.from_dlpack.html) | Returns a new array containing the data from another (array) object with a `__dlpack__` method. | +| Y | [`full`] | [`full`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.full.html) | Returns a new array having a specified `shape` and filled with `fill_value`. | +| Y | [`full_like`] | [`full_like`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.full_like.html) | Returns a new array filled with fill_value and having the same `shape` as an input array `x`. | +| Y | [`linspace`] | [`linspace`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.linspace.html) | Returns evenly spaced numbers over a specified interval. | +| Y | [`meshgrid`] | [`meshgrid`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.meshgrid.html) | Returns coordinate matrices from coordinate vectors. | +| Y | [`ones`] | [`ones`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.ones.html) | Returns a new array having a specified shape and filled with ones. | +| Y | [`ones_like`] | [`ones_like`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.ones_like.html) | Returns a new array filled with ones and having the same `shape` as an input array `x`. | +| Y | [`tril`] | [`tril`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.tril.html) | Returns the lower triangular part of a matrix (or a stack of matrices) `x`. | +| Y | [`triu`] | [`triu`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.triu.html) | Returns the upper triangular part of a matrix (or a stack of matrices) `x`. | +| Y | [`zeros`] | [`zeros`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.zeros.html) | Returns a new array having a specified `shape` and filled with zeros. | +| Y | [`zeros_like`] | [`zeros_like`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.zeros_like.html) | Returns a new array filled with zeros and having the same `shape` as an input array x. | **Partial implementation** - [`asarray`]: This function have different implementations for `Vec`, `[T; N]` and [`Tensor`]. Different signatures are utilized for different inputs and purposes. @@ -152,12 +152,12 @@ The reference implementation (as in [`DeviceCpuSerial`] and [`DeviceFaer`]), fol | status | implementation | Python API | description | |-|-|-|-| -| T | Rust type cast [`as`](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions)
[`DTypeCastAPI::into_cast`]
[`num::ToPrimitive`] | `astype` | Copies an array to a specified data type irrespective of Type Promotion Rules rules. | -| T | [`DTypePromoteAPI::CAN_CAST_SELF`]
[`DTypePromoteAPI::CAN_CAST_OTHER`]
operator trait definition | `can_cast` | Determines if one data type can be cast to another data type according Type Promotion Rules rules. | -| T | [`num::Float`] | `finfo` | Machine limits for floating-point data types. | -| T | [`num::Integer`] | `iinfo` | Machine limits for integer data types. | -| T | [`core::any::TypeId`] | `isdtype` | Returns a boolean indicating whether a provided dtype is of a specified data type "kind". | -| T | [`DTypePromoteAPI::Res`] | `result_type` | Returns the dtype that results from applying the type promotion rules (see Type Promotion Rules) to the arguments. | +| T | Rust type cast [`as`](https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions)
[`DTypeCastAPI::into_cast`]
[`num::ToPrimitive`] | [`astype`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.astype.html) | Copies an array to a specified data type irrespective of Type Promotion Rules rules. | +| T | [`DTypePromoteAPI::CAN_CAST_SELF`]
[`DTypePromoteAPI::CAN_CAST_OTHER`]
operator trait definition | [`can_cast`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.can_cast.html) | Determines if one data type can be cast to another data type according Type Promotion Rules rules. | +| T | [`num::Float`] | [`finfo`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.finfo.html) | Machine limits for floating-point data types. | +| T | [`num::Integer`] | [`iinfo`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.iinfo.html) | Machine limits for integer data types. | +| T | [`core::any::TypeId`] | [`isdtype`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.isdtype.html) | Returns a boolean indicating whether a provided dtype is of a specified data type "kind". | +| T | [`DTypePromoteAPI::Res`] | [`result_type`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.result_type.html) | Returns the dtype that results from applying the type promotion rules (see Type Promotion Rules) to the arguments. | ### Data Type Categories @@ -178,90 +178,90 @@ The reference implementation (as in [`DeviceCpuSerial`] and [`DeviceFaer`]), fol | status | implementation | Python API | description | |-|-|-|-| -| [`ExtNum`] | [`abs`] | `abs` | Calculates the absolute value for each element x_i of the input array x. | -| [`ComplexFloat`] | [`acos`] | `acos` | Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element x_i of the input array x. | -| [`ComplexFloat`] | [`acosh`] | `acosh` | Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element x_i of the input array x. | -| [`ComplexFloat`] | [`asin`] | `asin` | Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element x_i of the input array x. | -| [`ComplexFloat`] | [`asinh`] | `asinh` | Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element x_i in the input array x. | -| [`ComplexFloat`] | [`atan`] | `atan` | Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element x_i of the input array x. | -| [`ComplexFloat`] | [`atanh`] | `atanh` | Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element x_i of the input array x. | -| [`Not`] | `!`, [`not`] | `bitwise_invert` | Inverts (flips) each bit for each element x_i of the input array x. | -| [`Float`] | [`ceil`] | `ceil` | 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. | -| [`ComplexFloat`] | [`conj`] | `conj` | Returns the complex conjugate for each element x_i of the input array x. | -| [`ComplexFloat`] | [`cos`] | `cos` | Calculates an implementation-dependent approximation to the cosine for each element x_i of the input array x. | -| [`ComplexFloat`] | [`cosh`] | `cosh` | Calculates an implementation-dependent approximation to the hyperbolic cosine for each element x_i in the input array x. | -| [`ComplexFloat`] | [`exp`] | `exp` | 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). | -| [`Float`] (partial) | [`expm1`] | `expm1` | Calculates an implementation-dependent approximation to exp(x)-1 for each element x_i of the input array x. | -| [`Float`] | [`floor`] | `floor` | 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. | -| [`ExtNum`] | [`imag`] | `imag` | Returns the imaginary component of a complex number for each element x_i of the input array x. | -| [`ComplexFloat`] | [`is_finite`] | `isfinite` | Tests each element x_i of the input array x to determine if finite. | -| [`ComplexFloat`] | [`is_inf`] | `isinf` | Tests each element x_i of the input array x to determine if equal to positive or negative infinity. | -| [`ComplexFloat`] | [`is_nan`] | `isnan` | Tests each element x_i of the input array x to determine whether the element is NaN. | -| [`ComplexFloat`] | [`log`] | `log` | Calculates an implementation-dependent approximation to the natural (base e) logarithm for each element x_i of the input array x. | -| Not implemented | | `log1p` | 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. | -| [`ComplexFloat`] | [`log2`] | `log2` | Calculates an implementation-dependent approximation to the base 2 logarithm for each element x_i of the input array x. | -| [`ComplexFloat`] | [`log10`] | `log10` | Calculates an implementation-dependent approximation to the base 10 logarithm for each element x_i of the input array x. | -| [`Not`] | [`not`] instead | `logical_not` | Computes the logical NOT for each element x_i of the input array x. | -| [`Neg`] | `-`, [`neg`] | `negative` | Computes the numerical negative of each element x_i (i.e., y_i = -x_i) of the input array x. | -| Dropped | | `positive` | Computes the numerical positive of each element x_i (i.e., y_i = +x_i) of the input array x. | -| [`ExtNum`] | [`real`] | `real` | Returns the real component of a complex number for each element x_i of the input array x. | -| [`ComplexFloat`] | [`reciprocal`] | `reciprocal` | Returns the reciprocal for each element x_i of the input array x. | -| [`Float`] | [`round`] | `round` | Rounds each element x_i of the input array x to the nearest integer-valued number. | -| [`ComplexFloat`] | [`sign`] | `sign` | Returns an indication of the sign of a number for each element x_i of the input array x. | -| [`Signed`] | [`signbit`] | `signbit` | Determines whether the sign bit is set for each element x_i of the input array x. | -| [`ComplexFloat`] | [`sin`] | `sin` | Calculates an implementation-dependent approximation to the sine for each element x_i of the input array x. | -| [`ComplexFloat`] | [`sinh`] | `sinh` | Calculates an implementation-dependent approximation to the hyperbolic sine for each element x_i of the input array x. | -| [`Num`] | [`square`] | `square` | Squares each element x_i of the input array x. | -| [`ComplexFloat`] | [`sqrt`] | `sqrt` | Calculates the principal square root for each element x_i of the input array x. | -| [`ComplexFloat`] | [`tan`] | `tan` | Calculates an implementation-dependent approximation to the tangent for each element x_i of the input array x. | -| [`ComplexFloat`] | [`tanh`] | `tanh` | Calculates an implementation-dependent approximation to the hyperbolic tangent for each element x_i of the input array x. | -| [`Float`] | [`trunc`] | `trunc` | Rounds each element x_i of the input array x to the nearest integer-valued number that is closer to zero than x_i. | +| [`ExtNum`] | [`abs`] | [`abs`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.abs.html) | Calculates the absolute value for each element x_i of the input array x. | +| [`ComplexFloat`] | [`acos`] | [`acos`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.acos.html) | Calculates an implementation-dependent approximation of the principal value of the inverse cosine for each element x_i of the input array x. | +| [`ComplexFloat`] | [`acosh`] | [`acosh`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.acosh.html) | Calculates an implementation-dependent approximation to the inverse hyperbolic cosine for each element x_i of the input array x. | +| [`ComplexFloat`] | [`asin`] | [`asin`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.asin.html) | Calculates an implementation-dependent approximation of the principal value of the inverse sine for each element x_i of the input array x. | +| [`ComplexFloat`] | [`asinh`] | [`asinh`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.asinh.html) | Calculates an implementation-dependent approximation to the inverse hyperbolic sine for each element x_i in the input array x. | +| [`ComplexFloat`] | [`atan`] | [`atan`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.atan.html) | Calculates an implementation-dependent approximation of the principal value of the inverse tangent for each element x_i of the input array x. | +| [`ComplexFloat`] | [`atanh`] | [`atanh`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.atanh.html) | Calculates an implementation-dependent approximation to the inverse hyperbolic tangent for each element x_i of the input array x. | +| [`Not`] | `!`, [`not`] | [`bitwise_invert`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.bitwise_invert.html) | Inverts (flips) each bit for each element x_i of the input array x. | +| [`Float`] | [`ceil`] | [`ceil`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.ceil.html) | 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. | +| [`ComplexFloat`] | [`conj`] | [`conj`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.conj.html) | Returns the complex conjugate for each element x_i of the input array x. | +| [`ComplexFloat`] | [`cos`] | [`cos`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.cos.html) | Calculates an implementation-dependent approximation to the cosine for each element x_i of the input array x. | +| [`ComplexFloat`] | [`cosh`] | [`cosh`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.cosh.html) | Calculates an implementation-dependent approximation to the hyperbolic cosine for each element x_i in the input array x. | +| [`ComplexFloat`] | [`exp`] | [`exp`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.exp.html) | 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). | +| [`Float`] (partial) | [`expm1`] | [`expm1`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.expm1.html) | Calculates an implementation-dependent approximation to exp(x)-1 for each element x_i of the input array x. | +| [`Float`] | [`floor`] | [`floor`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.floor.html) | 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. | +| [`ExtNum`] | [`imag`] | [`imag`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.imag.html) | Returns the imaginary component of a complex number for each element x_i of the input array x. | +| [`ComplexFloat`] | [`is_finite`] | [`isfinite`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.isfinite.html) | Tests each element x_i of the input array x to determine if finite. | +| [`ComplexFloat`] | [`is_inf`] | [`isinf`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.isinf.html) | Tests each element x_i of the input array x to determine if equal to positive or negative infinity. | +| [`ComplexFloat`] | [`is_nan`] | [`isnan`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.isnan.html) | Tests each element x_i of the input array x to determine whether the element is NaN. | +| [`ComplexFloat`] | [`log`] | [`log`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.log.html) | Calculates an implementation-dependent approximation to the natural (base e) logarithm for each element x_i of the input array x. | +| Not implemented | | [`log1p`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.log1p.html) | 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. | +| [`ComplexFloat`] | [`log2`] | [`log2`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.log2.html) | Calculates an implementation-dependent approximation to the base 2 logarithm for each element x_i of the input array x. | +| [`ComplexFloat`] | [`log10`] | [`log10`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.log10.html) | Calculates an implementation-dependent approximation to the base 10 logarithm for each element x_i of the input array x. | +| [`Not`] | [`not`] instead | [`logical_not`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.logical_not.html) | Computes the logical NOT for each element x_i of the input array x. | +| [`Neg`] | `-`, [`neg`] | [`negative`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.negative.html) | Computes the numerical negative of each element x_i (i.e., y_i = -x_i) of the input array x. | +| Dropped | | [`positive`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.positive.html) | Computes the numerical positive of each element x_i (i.e., y_i = +x_i) of the input array x. | +| [`ExtNum`] | [`real`] | [`real`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.real.html) | Returns the real component of a complex number for each element x_i of the input array x. | +| [`ComplexFloat`] | [`reciprocal`] | [`reciprocal`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.reciprocal.html) | Returns the reciprocal for each element x_i of the input array x. | +| [`Float`] | [`round`] | [`round`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.round.html) | Rounds each element x_i of the input array x to the nearest integer-valued number. | +| [`ComplexFloat`] | [`sign`] | [`sign`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.sign.html) | Returns an indication of the sign of a number for each element x_i of the input array x. | +| [`Signed`] | [`signbit`] | [`signbit`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.signbit.html) | Determines whether the sign bit is set for each element x_i of the input array x. | +| [`ComplexFloat`] | [`sin`] | [`sin`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.sin.html) | Calculates an implementation-dependent approximation to the sine for each element x_i of the input array x. | +| [`ComplexFloat`] | [`sinh`] | [`sinh`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.sinh.html) | Calculates an implementation-dependent approximation to the hyperbolic sine for each element x_i of the input array x. | +| [`Num`] | [`square`] | [`square`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.square.html) | Squares each element x_i of the input array x. | +| [`ComplexFloat`] | [`sqrt`] | [`sqrt`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.sqrt.html) | Calculates the principal square root for each element x_i of the input array x. | +| [`ComplexFloat`] | [`tan`] | [`tan`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.tan.html) | Calculates an implementation-dependent approximation to the tangent for each element x_i of the input array x. | +| [`ComplexFloat`] | [`tanh`] | [`tanh`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.tanh.html) | Calculates an implementation-dependent approximation to the hyperbolic tangent for each element x_i of the input array x. | +| [`Float`] | [`trunc`] | [`trunc`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.trunc.html) | Rounds each element x_i of the input array x to the nearest integer-valued number that is closer to zero than x_i. | ### Binary Functions | status | implementation | Python API | description | |-|-|-|-| -| [`Add`] | `+`, [`add`] | `add` | Calculates the sum for each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | -| [`Float`] | [`atan2`] | `atan2` | 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. | -| [`BitAnd`] | `&`, [`bitand`] | `bitwise_and` | 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. | -| [`Shl`] | `<<`, [`shl`] | `bitwise_left_shift` | 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. | -| [`BitOr`] | `\|`, [`bitor`] | `bitwise_or` | 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. | -| [`Shr`] | `>>`, [`shr`] | `bitwise_right_shift` | 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. | -| [`BitXor`] | `^`, [`bitxor`] | `bitwise_xor` | 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. | -| [`Float`] | [`copysign`] | `copysign` | 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. | -| [`Div`] | `/`, [`div`] | `divide` | Calculates the division of each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | -| [`PartialEq`] | [`eq`], [`equal`] | `equal` | 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. | -| [`ExtReal`] | [`floor_divide`] | `floor_divide` | 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. | -| [`PartialOrd`] | [`gt`], [`greater`] | `greater` | 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. | -| [`PartialOrd`] | [`ge`], [`greater_equal`] | `greater_equal` | 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. | -| [`Float`] | [`hypot`] | `hypot` | 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. | -| [`PartialOrd`] | [`lt`], [`less`] | `less` | 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. | -| [`PartialOrd`] | [`le`], [`less_equal`] | `less_equal` | 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. | -| [`ComplexFloat`] | [`log_add_exp`] | `logaddexp` | 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. | -| | [`bitand`] instead | `logical_and` | 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. | -| | [`bitor`] instead | `logical_or` | 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. | -| | [`bitxor`] instead | `logical_xor` | 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. | -| [`ExtReal`] | [`maximum`] | `maximum` | 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. | -| [`ExtReal`] | [`minimum`] | `minimum` | 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. | -| [`Mul`] | [`mul`] | `multiply` | Calculates the product for each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | -| [`ExtFloat`] | [`nextafter`] | `nextafter` | 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. | -| [`PartialEq`] | [`ne`], [`not_equal`] | `not_equal` | 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. | -| [`Pow`] | [`pow`] | `pow` | 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. | -| [`Rem`] | [`rt::rem`][^2] | `remainder` | 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. | -| [`Sub`] | `-`, [`sub`] | `subtract` | Calculates the difference for each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | +| [`Add`] | `+`, [`add`] | [`add`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.add.html) | Calculates the sum for each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | +| [`Float`] | [`atan2`] | [`atan2`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.atan2.html) | 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. | +| [`BitAnd`] | `&`, [`bitand`] | [`bitwise_and`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.bitwise_and.html) | 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. | +| [`Shl`] | `<<`, [`shl`] | [`bitwise_left_shift`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.bitwise_left_shift.html) | 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. | +| [`BitOr`] | `\|`, [`bitor`] | [`bitwise_or`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.bitwise_or.html) | 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. | +| [`Shr`] | `>>`, [`shr`] | [`bitwise_right_shift`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.bitwise_right_shift.html) | 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. | +| [`BitXor`] | `^`, [`bitxor`] | [`bitwise_xor`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.bitwise_xor.html) | 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. | +| [`Float`] | [`copysign`] | [`copysign`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.copysign.html) | 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. | +| [`Div`] | `/`, [`div`] | [`divide`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.divide.html) | Calculates the division of each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | +| [`PartialEq`] | [`eq`], [`equal`] | [`equal`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.equal.html) | 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. | +| [`ExtReal`] | [`floor_divide`] | [`floor_divide`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.floor_divide.html) | 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. | +| [`PartialOrd`] | [`gt`], [`greater`] | [`greater`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.greater.html) | 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. | +| [`PartialOrd`] | [`ge`], [`greater_equal`] | [`greater_equal`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.greater_equal.html) | 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. | +| [`Float`] | [`hypot`] | [`hypot`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.hypot.html) | 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. | +| [`PartialOrd`] | [`lt`], [`less`] | [`less`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.less.html) | 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. | +| [`PartialOrd`] | [`le`], [`less_equal`] | [`less_equal`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.less_equal.html) | 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. | +| [`ComplexFloat`] | [`log_add_exp`] | [`logaddexp`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.logaddexp.html) | 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. | +| | [`bitand`] instead | [`logical_and`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.logical_and.html) | 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. | +| | [`bitor`] instead | [`logical_or`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.logical_or.html) | 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. | +| | [`bitxor`] instead | [`logical_xor`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.logical_xor.html) | 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. | +| [`ExtReal`] | [`maximum`] | [`maximum`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.maximum.html) | 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. | +| [`ExtReal`] | [`minimum`] | [`minimum`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.minimum.html) | 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. | +| [`Mul`] | [`mul`] | [`multiply`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.multiply.html) | Calculates the product for each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | +| [`ExtFloat`] | [`nextafter`] | [`nextafter`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.nextafter.html) | 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. | +| [`PartialEq`] | [`ne`], [`not_equal`] | [`not_equal`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.not_equal.html) | 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. | +| [`Pow`] | [`pow`] | [`pow`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.pow.html) | 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. | +| [`Rem`] | [`rt::rem`][^2] | [`remainder`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.remainder.html) | 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. | +| [`Sub`] | `-`, [`sub`] | [`subtract`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.subtract.html) | Calculates the difference for each element x1_i of the input array x1 with the respective element x2_i of the input array x2. | ### Other functions | status | implementation | Python API | description | |-|-|-|-| -| | | `clip` | Clamps each element x_i of the input array x to the range [min, max]. | +| | | [`clip`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.clip.html) | Clamps each element x_i of the input array x to the range [min, max]. | ## Indexing Functions | status | implementation | Python API | description | |-|-|-|-| -| P | [`take`] | `take` | Returns elements of an array along an axis. | -| | | `take_along_axis` | Returns elements from an array at the one-dimensional indices specified by indices along a provided axis. | +| P | [`take`] | [`take`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.take.html) | Returns elements of an array along an axis. | +| | | [`take_along_axis`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.take_along_axis.html) | Returns elements from an array at the one-dimensional indices specified by indices along a provided axis. | **Partial implementation** - [`take`] currently only supports indexing from an axis, which is also the Python Array API requires. However, NumPy also allows `axis = None` to index the flattened array, which is not implemented in RSTSR. @@ -270,39 +270,40 @@ The reference implementation (as in [`DeviceCpuSerial`] and [`DeviceFaer`]), fol | status | implementation | Python API | description | |-|-|-|-| -| D | requires reflection | `capabilities` | Returns a dictionary of array library capabilities. | -| Fixed | [`DeviceCpu`] | `default_device` | Returns the default device. | -| D | controled by rust | `default_dtypes` | Returns a dictionary containing default data types. | -| Y | [`TensorBase::device`] | `devices` | Returns a list of supported devices which are available at runtime. | -| Y | [`core::any::type_name_of_val`] | `dtypes` | Returns a dictionary of supported Array API data types. | +| D | requires reflection | [`capabilities`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.into.capabilities.html) | Returns a dictionary of array library capabilities. | +| Fixed | [`DeviceCpu`] | [`default_device`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.info.default_device.html) | Returns the default device. | +| D | controled by rust | [`default_dtypes`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.info.default_dtypes.html) | Returns a dictionary containing default data types. | +| Y | [`TensorBase::device`] | [`devices`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.info.devices.html) | Returns a list of supported devices which are available at runtime. | +| Y | [`core::any::type_name_of_val`] | [`dtypes`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.info.dtypes.html) | Returns a dictionary of supported Array API data types. | ## Linear Algebra Functions | status | implementation | Python API | description | |-|-|-|-| -| Y | [`matmul()`] | `matmul` | Computes the matrix product. | -| Y | [`swapaxes`]`(-1, -2)` | `matrix_transpose` | Transposes a matrix (or a stack of matrices) x. | -| | | `tensordot` | Returns a tensor contraction of x1 and x2 over specific axes. | -| | | `vecdot` | Computes the (vector) dot product of two arrays. | +| Y | [`matmul()`] | [`matmul`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.matmul.html) | Computes the matrix product. | +| Y | [`swapaxes`]`(-1, -2)` | [`matrix_transpose`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.matrix_transpose.html) | Transposes a matrix (or a stack of matrices) x. | +| | | [`tensordot`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.tensordot.html) | Returns a tensor contraction of x1 and x2 over specific axes. | +| | | [`vecdot`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.vecdot.html) | Computes the (vector) dot product of two arrays. | ## Manipulation Functions | status | implementation | Python API | description | |-|-|-|-| -| Y | [`broadcast_arrays`] | [`broadcast_arrays`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.broadcast_arrays.html) | Broadcasts one or more arrays against one another. | -| Y | [`to_broadcast`] | [`broadcast_to`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.broadcast_to.html) | Broadcasts an array to a specified shape. | -| Y | [`concat`](concat()) | `concat` | Joins a sequence of arrays along an existing axis. | -| Y | [`expand_dims`] | [`expand_dims`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.expand_dims.html) | Expands the shape of an array by inserting a new axis (dimension) of size one at the position specified by `axis`. | -| Y | [`flip`] | [`flip`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.flip.html) | Reverses the order of elements in an array along the given axis. | -| | | `moveaxis` | Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. | -| Y | [`transpose`], [`permute_dims`] | [`permute_dims`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.permute_dims.html) | Permutes the axes (dimensions) of an array `x`. | -| | | `repeat` | Repeats each element of an array a specified number of times on a per-element basis. | -| P | [`reshape`], [`into_shape_assume_contig`] | [`reshape`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.reshape.html) | Reshapes an array without changing its data. | -| | | `roll` | Rolls array elements along a specified axis. | -| P | [`squeeze`] | [`squeeze`](https://data-apis.org/array-api/2024.12/API_specification/generated/array_api.squeeze.html) | Removes singleton dimensions (axes) from x. | -| Y | [`stack`] | `stack` | Joins a sequence of arrays along a new axis. | -| | | `tile` | Constructs an array by tiling an input array. | -| Y | [`unstack`] | `unstack` | Splits an array into a sequence of arrays along the given axis. | +| Y | [`broadcast_arrays`] | [`broadcast_arrays`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.broadcast_arrays.html) | Broadcasts one or more arrays against one another. | +| Y | [`to_broadcast`] | [`broadcast_to`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.broadcast_to.html) | Broadcasts an array to a specified shape. | +| | | [`broadcast_shapes`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.broadcast_shapes.html) | Broadcasts one or more shapes against one another. | +| Y | [`concat`](concat()) | [`concat`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.concat.html) | Joins a sequence of arrays along an existing axis. | +| Y | [`expand_dims`] | [`expand_dims`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.expand_dims.html) | Expands the shape of an array by inserting a new axis of size one at the position (or positions) specified by `axis`. | +| Y | [`flip`] | [`flip`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.flip.html) | Reverses the order of elements in an array along the given axis. | +| | | [`moveaxis`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.moveaxis.html) | Moves array axes (dimensions) to new positions, while leaving other axes in their original positions. | +| Y | [`transpose`], [`permute_dims`] | [`permute_dims`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.permute_dims.html) | Permutes the axes (dimensions) of an array `x`. | +| | | [`repeat`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.repeat.html) | Repeats each element of an array a specified number of times on a per-element basis. | +| P | [`reshape`], [`into_shape_assume_contig`] | [`reshape`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.reshape.html) | Reshapes an array without changing its data. | +| | | [`roll`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.roll.html) | Rolls array elements along a specified axis. | +| P | [`squeeze`] | [`squeeze`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.squeeze.html) | Removes singleton dimensions (axes) from x. | +| Y | [`stack`] | [`stack`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.stack.html) | Joins a sequence of arrays along a new axis. | +| | | [`tile`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.tile.html) | Constructs an array by tiling an input array. | +| Y | [`unstack`] | [`unstack`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.unstack.html) | Splits an array into a sequence of arrays along the given axis. | **Partial implementation** - [`squeeze`] accepts one axis as input, instead of accepting multiple axes. This is mostly because output of smaller dimension tensor can be fixed-dimension array ([`DimSmallerOneAPI::SmallerOne`]) when only one axis is passed as argument. @@ -312,53 +313,103 @@ The reference implementation (as in [`DeviceCpuSerial`] and [`DeviceFaer`]), fol | status | implementation | Python API | description | |-|-|-|-| -| Y | [`argmax`], [`argmax_axes`] | `argmax` | Returns the indices of the maximum values along a specified axis. | -| Y | [`argmin`], [`argmin_axes`] | `argmin` | Returns the indices of the minimum values along a specified axis. | -| Y | [`count_nonzero`], [`count_nonzero_axes`] | `count_nonzero` | Counts the number of array elements which are non-zero. | -| | | `nonzero` | Returns the indices of the array elements which are non-zero. | -| | | `searchsorted` | 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. | -| | | `where` | Returns elements chosen from x1 or x2 depending on condition. | +| Y | [`argmax`], [`argmax_axes`] | [`argmax`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.argmax.html) | Returns the indices of the maximum values along a specified axis. | +| Y | [`argmin`], [`argmin_axes`] | [`argmin`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.argmin.html) | Returns the indices of the minimum values along a specified axis. | +| Y | [`count_nonzero`], [`count_nonzero_axes`] | [`count_nonzero`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.count_nonzero.html) | Counts the number of array elements which are non-zero. | +| | | [`nonzero`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.nonzero.html) | Returns the indices of the array elements which are non-zero. | +| | | [`searchsorted`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.searchsorted.html) | 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. | +| | | [`where`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.where.html) | Returns elements chosen from x1 or x2 depending on condition. | ## Set Functions | status | implementation | Python API | description | |-|-|-|-| -| | | `unique_all` | 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. | -| | | `unique_counts` | Returns the unique elements of an input array x and the corresponding counts for each unique element in x. | -| | | `unique_inverse` | Returns the unique elements of an input array x and the indices from the set of unique elements that reconstruct x. | -| | | `unique_values` | Returns the unique elements of an input array x. | +| | | [`isin`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.isin.html) | Tests for each element in `x1` whether the element is in `x2`. | +| | | [`unique_all`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.unique_all.html) | 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. | +| | | [`unique_counts`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.unique_counts.html) | Returns the unique elements of an input array x and the corresponding counts for each unique element in x. | +| | | [`unique_inverse`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.unique_inverse.html) | Returns the unique elements of an input array x and the indices from the set of unique elements that reconstruct x. | +| | | [`unique_values`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.unique_values.html) | Returns the unique elements of an input array x. | ## Sorting Functions | status | implementation | Python API | description | |-|-|-|-| -| | | `argsort` | Returns the indices that sort an array x along a specified axis. | -| | | `sort` | Returns a sorted copy of an input array x. | +| | | [`argsort`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.argsort.html) | Returns the indices that sort an array x along a specified axis. | +| | | [`sort`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.sort.html) | Returns a sorted copy of an input array x. | ## Statistical Functions | status | implementation | Python API | description | |-|-|-|-| -| | | `cumulative_prod` | Calculates the cumulative product of elements in the input array x. | -| | | `cumulative_sum` | Calculates the cumulative sum of elements in the input array x. | -| Y | [`max`], [`max_axes`] | `max` | Calculates the maximum value of the input array x. | -| Y | [`mean`], [`mean_axes`] | `mean` | Calculates the arithmetic mean of the input array x. | -| Y | [`min`], [`min_axes`] | `min` | Calculates the minimum value of the input array x. | -| Y | [`prod`], [`prod_axes`] | `prod` | Calculates the product of input array x elements. | -| Y | [`std`], [`std_axes`] | `std` | Calculates the standard deviation of the input array x. | -| Y | [`sum`], [`sum_axes`] | `sum` | Calculates the sum of the input array x. | -| Y | [`var`], [`var_axes`] | `var` | Calculates the variance of the input array x. | +| | | [`cumulative_prod`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.cumulative_prod.html) | Calculates the cumulative product of elements in the input array x. | +| | | [`cumulative_sum`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.cumulative_sum.html) | Calculates the cumulative sum of elements in the input array x. | +| Y | [`max`], [`max_axes`] | [`max`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.max.html) | Calculates the maximum value of the input array x. | +| Y | [`mean`], [`mean_axes`] | [`mean`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.mean.html) | Calculates the arithmetic mean of the input array x. | +| Y | [`min`], [`min_axes`] | [`min`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.min.html) | Calculates the minimum value of the input array x. | +| Y | [`prod`], [`prod_axes`] | [`prod`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.prod.html) | Calculates the product of input array x elements. | +| Y | [`std`], [`std_axes`] | [`std`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.std.html) | Calculates the standard deviation of the input array x. | +| Y | [`sum`], [`sum_axes`] | [`sum`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.sum.html) | Calculates the sum of the input array x. | +| Y | [`var`], [`var_axes`] | [`var`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.var.html) | Calculates the variance of the input array x. | ## Utility Functions | status | implementation | Python API | description | |-|-|-|-| -| Y | [`all`], [`all_axes`] | `all` | Tests whether all input array elements evaluate to True along a specified axis. | -| Y | [`any`], [`any_axes`] | `any` | Tests whether any input array element evaluates to True along a specified axis. | -| | | `diff` | Calculates the n-th discrete forward difference along a specified axis. | +| Y | [`all`], [`all_axes`] | [`all`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.all.html) | Tests whether all input array elements evaluate to True along a specified axis. | +| Y | [`any`], [`any_axes`] | [`any`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.any.html) | Tests whether any input array element evaluates to True along a specified axis. | +| | | [`diff`](https://data-apis.org/array-api/latest/API_specification/generated/array_api.diff.html) | Calculates the n-th discrete forward difference along a specified axis. | + +## Fast Fourier Transform (extensions) + +| status | implementation | Python API | description | +|-|-|-|-| +| | | [`fft`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.fft.html) | Computes the one-dimensional discrete Fourier transform. | +| | | [`ifft`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.ifft.html) | Computes the one-dimensional inverse discrete Fourier transform. | +| | | [`fftn`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.fftn.html) | Computes the n-dimensional discrete Fourier transform. | +| | | [`ifftn`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.ifftn.html) | Computes the n-dimensional inverse discrete Fourier transform. | +| | | [`rfft`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.rfft.html) | Computes the one-dimensional discrete Fourier transform for real-valued input. | +| | | [`irfft`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.irfft.html) | Computes the one-dimensional inverse of `rfft` for complex-valued input. | +| | | [`rfftn`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.rfftn.html) | Computes the n-dimensional discrete Fourier transform for real-valued input. | +| | | [`irfftn`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.irfftn.html) | Computes the n-dimensional inverse of `rfftn` for complex-valued input. | +| | | [`hfft`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.hfft.html) | Computes the one-dimensional discrete Fourier transform of a signal with Hermitian symmetry. | +| | | [`ihfft`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.ihfft.html) | Computes the one-dimensional inverse discrete Fourier transform of a signal with Hermitian symmetry. | +| | | [`fftfreq`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.fftfreq.html) | Computes the discrete Fourier transform sample frequencies. | +| | | [`rfftfreq`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.rfftfreq.html) | Computes the discrete Fourier transform sample frequencies (for `rfft` and `irfft`). | +| | | [`fftshift`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.fftshift.html) | Shifts the zero-frequency component to the center of the spectrum. | +| | | [`ifftshift`](https://data-apis.org/array-api/latest/extensions/generated/array_api.fft.ifftshift.html) | Inverse of `fftshift`. | + +## Linear Algebra (extensions) + +| status | implementation | Python API | description | +|-|-|-|-| +| | | [`cholesky`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.cholesky.html) | Returns the lower (upper) Cholesky decomposition of a complex Hermitian or real symmetric positive-definite matrix `x`. | +| | | [`cross`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.cross.html) | Returns the cross product of 3-element vectors. | +| | | [`det`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.det.html) | Returns the determinant of a square matrix (or a stack of square matrices) `x`. | +| | | [`diagonal`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.diagonal.html) | Returns the specified diagonals of a matrix (or a stack of matrices) `x`. | +| | | [`eigh`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.eigh.html) | Returns an eigenvalue decomposition of a complex Hermitian or real symmetric matrix (or a stack of matrices) `x`. | +| | | [`eigvalsh`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.eigvalsh.html) | Returns the eigenvalues of a complex Hermitian or real symmetric matrix (or a stack of matrices) `x`. | +| | | [`inv`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.inv.html) | Returns the multiplicative inverse of a square matrix (or a stack of square matrices) `x`. | +| | | [`matmul`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.matmul.html) | Computes the matrix product. | +| | | [`matrix_norm`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.matrix_norm.html) | Computes the matrix norm of a matrix (or a stack of matrices) `x`. | +| | | [`matrix_power`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.matrix_power.html) | Raises a square matrix (or a stack of square matrices) `x` to an integer power `n`. | +| | | [`matrix_rank`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.matrix_rank.html) | Returns the rank (i.e., number of non-zero singular values) of a matrix (or a stack of matrices). | +| | | [`matrix_transpose`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.matrix_transpose.html) | Transposes a matrix (or a stack of matrices) x. | +| | | [`outer`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.outer.html) | Returns the outer product of two vectors `x1` and `x2`. | +| | | [`pinv`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.pinv.html) | Returns the (Moore-Penrose) pseudo-inverse of a matrix (or a stack of matrices) `x`. | +| | | [`qr`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.qr.html) | Returns the QR decomposition of a full column rank matrix (or a stack of matrices). | +| | | [`slogdet`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.slogdet.html) | 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`. | +| | | [`solve`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.solve.html) | Returns the solution of a square system of linear equations with a unique solution. | +| | | [`svd`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.svd.html) | Returns a singular value decomposition (SVD) of a matrix (or a stack of matrices) `x`. | +| | | [`svdvals`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.svdvals.html) | Returns the singular values of a matrix (or a stack of matrices) `x`. | +| | | [`tensordot`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.tensordot.html) | Returns a tensor contraction of x1 and x2 over specific axes. | +| | | [`trace`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.trace.html) | Returns the sum along the specified diagonals of a matrix (or a stack of matrices) `x`. | +| | | [`vecdot`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.vecdot.html) | Computes the (vector) dot product of two arrays. | +| | | [`vector_norm`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.vector_norm.html) | Computes the vector norm of a vector (or batch of vectors) `x`. | +| | | [`eig`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.eig.html) | Returns eigenvalues and eigenvectors of a real or complex matrix (or stack of matrices) `x`. (optional extension) | +| | | [`eigvals`](https://data-apis.org/array-api/latest/extensions/generated/array_api.linalg.eigvals.html) | Returns the eigenvalues of a real or complex matrix (or a stack of matrices) `x`. (optional extension) | ## Other Dropped Specifications We decide to **drop** some supports in Python Array API: - **Reflected (swapped) operands.** A typical function in python is [`__radd__`](https://docs.python.org/3/reference/datamodel.html#object.__radd__). Reflected operands are not easy to be implemented in rust. I believe that in python, this is realized by checking dynamic object type; this is not friendly to language that requires compilation. -- **Functions related to Python Array API namespace and dlpack.** These routines are mostly for forcing other python packages to be compatible to Python Array API. This is not possible for another language currently. +- **Functions related to Python Array API namespace and dlpack.** These routines are mostly for forcing other python packages to be compatible to Python Array API. This is not possible for another language currently. \ No newline at end of file From 27b33e86b427c9ffbb83fa47b0a7754e8fea199e Mon Sep 17 00:00:00 2001 From: ajz34 Date: Wed, 25 Feb 2026 15:41:36 +0800 Subject: [PATCH 2/5] test -- testing framework updated for DeviceCpuSerial --- .../tests/tests_core/manuplication/mod.rs | 3 + .../tests/tests_core/manuplication/reshape.rs | 156 ++++++++++++++++++ rstsr-core/tests/tests_core/mod.rs | 1 + rstsr-core/tests/tests_core_row.rs | 12 ++ rstsr-core/tests/tests_utils/mod.rs | 59 +++++++ 5 files changed, 231 insertions(+) create mode 100644 rstsr-core/tests/tests_core/manuplication/mod.rs create mode 100644 rstsr-core/tests/tests_core/manuplication/reshape.rs create mode 100644 rstsr-core/tests/tests_core/mod.rs create mode 100644 rstsr-core/tests/tests_core_row.rs create mode 100644 rstsr-core/tests/tests_utils/mod.rs diff --git a/rstsr-core/tests/tests_core/manuplication/mod.rs b/rstsr-core/tests/tests_core/manuplication/mod.rs new file mode 100644 index 0000000..4650aa7 --- /dev/null +++ b/rstsr-core/tests/tests_core/manuplication/mod.rs @@ -0,0 +1,3 @@ +pub mod reshape; + +pub static CATEGORY: &str = "manuplication"; diff --git a/rstsr-core/tests/tests_core/manuplication/reshape.rs b/rstsr-core/tests/tests_core/manuplication/reshape.rs new file mode 100644 index 0000000..6a0a46f --- /dev/null +++ b/rstsr-core/tests/tests_core/manuplication/reshape.rs @@ -0,0 +1,156 @@ +use rstsr::prelude::*; + +use super::CATEGORY; +use crate::TESTCFG; + +#[cfg(test)] +mod docs_reshape { + use super::*; + static FUNC: &str = "docs_reshape"; + + #[test] + #[rustfmt::skip] + fn quick_start() { + crate::specify_test!("quick_start"); + + let mut device = TESTCFG.device.clone(); + device.set_default_order(RowMajor); + + let a = rt::arange((6, &device)); + let a_reshaped = a.reshape([2, 3]); + let a_expected = rt::tensor_from_nested!( + [[0, 1, 2], [3, 4, 5]], + &device); + assert!(rt::allclose(&a_reshaped, &a_expected, None)); + + // in this case, unspecified axes length is inferred as 6 / 3 = 2 + let a_reshaped = a.reshape([3, -1]); + let a_expected = rt::tensor_from_nested!( + [[0, 1], [2, 3], [4, 5]], + &device); + assert!(rt::allclose(&a_reshaped, &a_expected, None)); + } + + #[test] + fn elaborated_diff_row_col() { + crate::specify_test!("elaborated_diff_row_col"); + + let mut device = TESTCFG.device.clone(); + device.set_default_order(RowMajor); + let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); + let b = a.reshape([3, 2]); + let a_vec = a.iter().collect::>(); + let b_vec = b.iter().collect::>(); + assert_eq!(a_vec, b_vec); // iterated sequence is the same + + let mut device = DeviceCpu::default(); + device.set_default_order(ColMajor); + let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); + let b = a.reshape([3, 2]); + let a_c_vec = a.iter().collect::>(); + let b_c_vec = b.iter().collect::>(); + assert_eq!(a_c_vec, b_c_vec); // iterated sequence is the same + assert_ne!(a_c_vec, a_vec); // iterated sequence is different from row-major + + // Row-major reshape + let mut device = DeviceCpu::default(); + device.set_default_order(RowMajor); + // a: [[0, 1, 2], [3, 4, 5]] + // b: [[0, 1], [2, 3], [4, 5]] + // iterated sequence: [0, 1, 2, 3, 4, 5] + let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); + let b = a.reshape([3, 2]); + let b_expected = rt::tensor_from_nested!([[0, 1], [2, 3], [4, 5]], &device); + assert!(rt::allclose(&b, &b_expected, None)); + let a_vec = a.iter().cloned().collect::>(); + let b_vec = b.iter().cloned().collect::>(); + assert_eq!(a_vec, b_vec); // iterated sequence is the same + assert_eq!(a_vec, vec![0, 1, 2, 3, 4, 5]); + + // Column-major reshape + let mut device = DeviceCpu::default(); + device.set_default_order(ColMajor); + // a: [[0, 1, 2], [3, 4, 5]] + // b: [[0, 4], [3, 2], [1, 5]] + // iterated sequence: [0, 3, 1, 4, 2, 5] + let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); + let b = a.reshape([3, 2]); + let b_expected = rt::tensor_from_nested!([[0, 4], [3, 2], [1, 5]], &device); + assert!(rt::allclose(&b, &b_expected, None)); + let a_vec = a.iter().cloned().collect::>(); + let b_vec = b.iter().cloned().collect::>(); + assert_eq!(a_vec, b_vec); // iterated sequence is the same + assert_eq!(a_vec, vec![0, 3, 1, 4, 2, 5]); + } + + #[test] + fn elaborated_clone_occasion() { + crate::specify_test!("elaborated_clone_occasion"); + + let mut device = TESTCFG.device.clone(); + device.set_default_order(RowMajor); + + // some strided tensor + // shape: (4, 6, 9), stride: (72, 9, 1), not c-contiguous + // contiguous situation: (4, [6, 9]), or say the last two dimensions are contiguous + let a = rt::arange((288, &device)).into_shape([4, 8, 9]).into_slice((.., 0..6, ..)); + assert_eq!(a.shape(), &[4, 6, 9]); + assert_eq!(a.stride(), &[72, 9, 1]); + assert!(!a.c_contig()); + + // reshape that does not require clone (outputs tensor view) + + // split a single dimension into multiple dimensions + assert!(!a.reshape([2, 2, 6, 9]).is_owned()); // (4, 6, 9) -> ([2, 2], 6, 9) + assert!(!a.reshape([4, 3, 2, 9]).is_owned()); // (4, 6, 9) -> (4, [3, 2], 9) + assert!(!a.reshape([4, 2, 3, 3, 3]).is_owned()); // (4, 6, 9) -> (4, [2, 3], [3, 3]) + + // merge contiguous dimensions into a single dimension + assert!(!a.reshape([4, 54]).is_owned()); // (4, 6, 9) -> (4, 6 * 9) + + // merge contiguous dimensions and then split + assert!(!a.reshape([4, 3, 6, 3]).is_owned()); // (4, [6, 9]) -> (4, [3, 6, 3]) + + // reshape that requires clone (outputs owned tensor) + + // merge non-contiguous dimensions + assert!(a.reshape([24, 9]).is_owned()); // (4, 6, 9) -> (4 * 6, 9) + assert!(a.reshape(-1).is_owned()); // (4, 6, 9) -> (4 * 6 * 9) + assert!(a.reshape([12, 2, 9]).is_owned()); // (4, 6, 9) -> (4 * [3, 2], 9) + } + + #[test] + fn into_shape() { + crate::specify_test!("into_shape"); + + let mut device = TESTCFG.device.clone(); + device.set_default_order(RowMajor); + + let a = rt::arange((6, &device)).into_shape([2, 3]); + println!("a: {:?}", a); + + // shape: (4, 6, 9), stride: (-54, 9, 1), not c-contiguous + // contiguous situation: (4, [6, 9]); the first dimension is reversed + let a = rt::arange((216, &device)).into_shape([4, 6, 9]).into_flip(0); + let a_ptr = a.raw().as_ptr(); + let b = a.into_shape([4, 54]); + let b_ptr = b.raw().as_ptr(); + assert_eq!(a_ptr, b_ptr); // contiguous dims merged, no data clone happened + + // shape: (4, 6, 9), stride: (-54, 9, 1), not c-contiguous + // contiguous situation: (4, [6, 9]); the first dimension is reversed + let a = rt::arange((216, &device)).into_shape([4, 6, 9]).into_flip(0); + let a_ptr = a.raw().as_ptr(); + let b = a.into_shape([24, 9]); + let b_ptr = b.raw().as_ptr(); + assert_ne!(a_ptr, b_ptr); // layout not compatible, data clone happened + + // shape: (4, 6, 9), stride: (72, 9, 1), not c-contiguous + // contiguous situation: (4, [6, 9]), or say the last two dimensions are contiguous + let a = rt::arange((288, &device)).into_shape([4, 8, 9]).into_slice((.., 0..6, ..)); + let a_ptr = a.raw().as_ptr(); + let b = a.into_shape([4, 54]); + let b_ptr = b.raw().as_ptr(); + assert_ne!(a_ptr, b_ptr); // layout-compatible, but input tensor is not compact (216 < 288) + } +} diff --git a/rstsr-core/tests/tests_core/mod.rs b/rstsr-core/tests/tests_core/mod.rs new file mode 100644 index 0000000..0c7276d --- /dev/null +++ b/rstsr-core/tests/tests_core/mod.rs @@ -0,0 +1 @@ +pub mod manuplication; diff --git a/rstsr-core/tests/tests_core_row.rs b/rstsr-core/tests/tests_core_row.rs new file mode 100644 index 0000000..3ffad1d --- /dev/null +++ b/rstsr-core/tests/tests_core_row.rs @@ -0,0 +1,12 @@ +mod tests_core; +mod tests_utils; + +use rstsr::prelude::*; +use std::sync::LazyLock; +use tests_utils::TestCfg; + +pub static TESTCFG: LazyLock> = LazyLock::new(|| { + let mut device = DeviceCpuSerial::default(); + device.set_default_order(RowMajor); + TestCfg::init(device, vec![], None) +}); diff --git a/rstsr-core/tests/tests_utils/mod.rs b/rstsr-core/tests/tests_utils/mod.rs new file mode 100644 index 0000000..42c4549 --- /dev/null +++ b/rstsr-core/tests/tests_utils/mod.rs @@ -0,0 +1,59 @@ +//! Utilities of tests. + +/// Test configuration. +pub struct TestCfg { + /// Device instance (commonly used) to run the test on. + pub device: B, + + /// Test cases to skip. + pub skip: Vec>, + + /// Test to run. If None, all tests are allowed to run. + pub allow: Option>>, + + /// Verbose mode. If true, print the skipped test cases. + pub verbose: bool, +} + +impl TestCfg { + pub fn init(device: B, skip: Vec<&'static str>, allow: Option>) -> Self { + // split skip and allow by "::" + let skip = skip.into_iter().map(|s| s.split("::").collect()).collect(); + let allow = allow.map(|allow| allow.into_iter().map(|s| s.split("::").collect()).collect()); + Self { device, skip, allow, verbose: true } + } + + /// Check if the test case with the given name should be skipped. + pub fn to_test(&self, test_name: &[&str]) -> bool { + // If any sequence in skip is a contiguous subsequence of test_name, skip the test. + // For example, test_name `A::B::C::D`, then `B::C` will skip the test, but `A::C` will not. + if self.skip.iter().any(|skip| test_name.windows(skip.len()).any(|w| w == skip)) { + if self.verbose { + eprintln!("skip test {}", test_name.join("::")); + } + return false; + } + // Only the sequence that starts with the prefix of test_name is allowed. + // For example, test_name `A::B::C::D`, then `A::B` will allow the test, but `B::C` will not. + if let Some(allow) = &self.allow { + if !allow.iter().any(|allow| test_name.starts_with(allow)) { + if self.verbose { + eprintln!("skip test {}", test_name.join("::")); + } + return false; + } + } + true + } +} + +#[macro_export] +macro_rules! specify_test { + ($item:literal) => {{ + static ITEM: &str = stringify!($item); + if !TESTCFG.to_test(&[CATEGORY, FUNC, ITEM]) { + eprintln!("skip test {CATEGORY}::{FUNC}::{ITEM}"); + return; + } + }}; +} From 455f18f6df6ef74e67f15fbeb3c4b18cc572d1e9 Mon Sep 17 00:00:00 2001 From: ajz34 Date: Wed, 25 Feb 2026 16:24:38 +0800 Subject: [PATCH 3/5] test -- add reshape test --- rstsr-core/src/storage/device.rs | 4 + .../src/tensor/manuplication/reshape.rs | 147 ------------------ rstsr-core/src/tensorbase.rs | 4 + .../tests/tests_core/manuplication/reshape.rs | 41 ++++- rstsr-core/tests/tests_utils/equality.rs | 27 ++++ rstsr-core/tests/tests_utils/mod.rs | 4 + 6 files changed, 73 insertions(+), 154 deletions(-) create mode 100644 rstsr-core/tests/tests_utils/equality.rs diff --git a/rstsr-core/src/storage/device.rs b/rstsr-core/src/storage/device.rs index 3271597..cf5f66a 100644 --- a/rstsr-core/src/storage/device.rs +++ b/rstsr-core/src/storage/device.rs @@ -62,6 +62,10 @@ where &self.device } + pub fn device_mut(&mut self) -> &mut B { + &mut self.device + } + pub fn data(&self) -> &R { &self.data } diff --git a/rstsr-core/src/tensor/manuplication/reshape.rs b/rstsr-core/src/tensor/manuplication/reshape.rs index d0170fc..50f7e2f 100644 --- a/rstsr-core/src/tensor/manuplication/reshape.rs +++ b/rstsr-core/src/tensor/manuplication/reshape.rs @@ -737,150 +737,3 @@ where } /* #endregion */ - -#[cfg(test)] -mod tests { - #[test] - #[rustfmt::skip] - fn doc_reshape() { - use rstsr::prelude::*; - let mut device = DeviceCpu::default(); - device.set_default_order(RowMajor); - - let a = rt::arange((6, &device)); - let a_reshaped = a.reshape([2, 3]); - let a_expected = rt::tensor_from_nested!( - [[0, 1, 2], [3, 4, 5]], - &device); - assert!(rt::allclose(&a_reshaped, &a_expected, None)); - - // in this case, unspecified axes length is inferred as 6 / 3 = 2 - let a_reshaped = a.reshape([3, -1]); - let a_expected = rt::tensor_from_nested!( - [[0, 1], [2, 3], [4, 5]], - &device); - assert!(rt::allclose(&a_reshaped, &a_expected, None)); - } - - #[test] - fn doc_reshape_elaborated_diff_row_col() { - use rstsr::prelude::*; - - let mut device = DeviceCpu::default(); - device.set_default_order(RowMajor); - let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); - let b = a.reshape([3, 2]); - let a_vec = a.iter().collect::>(); - let b_vec = b.iter().collect::>(); - assert_eq!(a_vec, b_vec); // iterated sequence is the same - - let mut device = DeviceCpu::default(); - device.set_default_order(ColMajor); - let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); - let b = a.reshape([3, 2]); - let a_c_vec = a.iter().collect::>(); - let b_c_vec = b.iter().collect::>(); - assert_eq!(a_c_vec, b_c_vec); // iterated sequence is the same - assert_ne!(a_c_vec, a_vec); // iterated sequence is different from row-major - - // Row-major reshape - let mut device = DeviceCpu::default(); - device.set_default_order(RowMajor); - // a: [[0, 1, 2], [3, 4, 5]] - // b: [[0, 1], [2, 3], [4, 5]] - // iterated sequence: [0, 1, 2, 3, 4, 5] - let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); - let b = a.reshape([3, 2]); - let b_expected = rt::tensor_from_nested!([[0, 1], [2, 3], [4, 5]], &device); - assert!(rt::allclose(&b, &b_expected, None)); - let a_vec = a.iter().cloned().collect::>(); - let b_vec = b.iter().cloned().collect::>(); - assert_eq!(a_vec, b_vec); // iterated sequence is the same - assert_eq!(a_vec, vec![0, 1, 2, 3, 4, 5]); - - // Column-major reshape - let mut device = DeviceCpu::default(); - device.set_default_order(ColMajor); - // a: [[0, 1, 2], [3, 4, 5]] - // b: [[0, 4], [3, 2], [1, 5]] - // iterated sequence: [0, 3, 1, 4, 2, 5] - let a = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); - let b = a.reshape([3, 2]); - let b_expected = rt::tensor_from_nested!([[0, 4], [3, 2], [1, 5]], &device); - assert!(rt::allclose(&b, &b_expected, None)); - let a_vec = a.iter().cloned().collect::>(); - let b_vec = b.iter().cloned().collect::>(); - assert_eq!(a_vec, b_vec); // iterated sequence is the same - assert_eq!(a_vec, vec![0, 3, 1, 4, 2, 5]); - } - - #[test] - fn doc_reshape_elaborated_clone_occasion() { - use rstsr::prelude::*; - - let mut device = DeviceCpu::default(); - device.set_default_order(RowMajor); - - // some strided tensor - // shape: (4, 6, 9), stride: (72, 9, 1), not c-contiguous - // contiguous situation: (4, [6, 9]), or say the last two dimensions are contiguous - let a = rt::arange((288, &device)).into_shape([4, 8, 9]).into_slice((.., 0..6, ..)); - assert_eq!(a.shape(), &[4, 6, 9]); - assert_eq!(a.stride(), &[72, 9, 1]); - assert!(!a.c_contig()); - - // reshape that does not require clone (outputs tensor view) - - // split a single dimension into multiple dimensions - assert!(!a.reshape([2, 2, 6, 9]).is_owned()); // (4, 6, 9) -> ([2, 2], 6, 9) - assert!(!a.reshape([4, 3, 2, 9]).is_owned()); // (4, 6, 9) -> (4, [3, 2], 9) - assert!(!a.reshape([4, 2, 3, 3, 3]).is_owned()); // (4, 6, 9) -> (4, [2, 3], [3, 3]) - - // merge contiguous dimensions into a single dimension - assert!(!a.reshape([4, 54]).is_owned()); // (4, 6, 9) -> (4, 6 * 9) - - // merge contiguous dimensions and then split - assert!(!a.reshape([4, 3, 6, 3]).is_owned()); // (4, [6, 9]) -> (4, [3, 6, 3]) - - // reshape that requires clone (outputs owned tensor) - - // merge non-contiguous dimensions - assert!(a.reshape([24, 9]).is_owned()); // (4, 6, 9) -> (4 * 6, 9) - assert!(a.reshape(-1).is_owned()); // (4, 6, 9) -> (4 * 6 * 9) - assert!(a.reshape([12, 2, 9]).is_owned()); // (4, 6, 9) -> (4 * [3, 2], 9) - } - - #[test] - fn doc_into_shape() { - use rstsr::prelude::*; - let mut device = DeviceCpu::default(); - device.set_default_order(RowMajor); - - let a = rt::arange((6, &device)).into_shape([2, 3]); - println!("a: {:?}", a); - - // shape: (4, 6, 9), stride: (-54, 9, 1), not c-contiguous - // contiguous situation: (4, [6, 9]); the first dimension is reversed - let a = rt::arange((216, &device)).into_shape([4, 6, 9]).into_flip(0); - let a_ptr = a.raw().as_ptr(); - let b = a.into_shape([4, 54]); - let b_ptr = b.raw().as_ptr(); - assert_eq!(a_ptr, b_ptr); // contiguous dims merged, no data clone happened - - // shape: (4, 6, 9), stride: (-54, 9, 1), not c-contiguous - // contiguous situation: (4, [6, 9]); the first dimension is reversed - let a = rt::arange((216, &device)).into_shape([4, 6, 9]).into_flip(0); - let a_ptr = a.raw().as_ptr(); - let b = a.into_shape([24, 9]); - let b_ptr = b.raw().as_ptr(); - assert_ne!(a_ptr, b_ptr); // layout not compatible, data clone happened - - // shape: (4, 6, 9), stride: (72, 9, 1), not c-contiguous - // contiguous situation: (4, [6, 9]), or say the last two dimensions are contiguous - let a = rt::arange((288, &device)).into_shape([4, 8, 9]).into_slice((.., 0..6, ..)); - let a_ptr = a.raw().as_ptr(); - let b = a.into_shape([4, 54]); - let b_ptr = b.raw().as_ptr(); - assert_ne!(a_ptr, b_ptr); // layout-compatible, but input tensor is not compact (216 < 288) - } -} diff --git a/rstsr-core/src/tensorbase.rs b/rstsr-core/src/tensorbase.rs index 8aa4cbf..ffffae2 100644 --- a/rstsr-core/src/tensorbase.rs +++ b/rstsr-core/src/tensorbase.rs @@ -136,6 +136,10 @@ where self.storage().device() } + pub fn device_mut(&mut self) -> &mut B { + self.storage_mut().device_mut() + } + pub fn data(&self) -> &R { self.storage().data() } diff --git a/rstsr-core/tests/tests_core/manuplication/reshape.rs b/rstsr-core/tests/tests_core/manuplication/reshape.rs index 6a0a46f..fa15bc9 100644 --- a/rstsr-core/tests/tests_core/manuplication/reshape.rs +++ b/rstsr-core/tests/tests_core/manuplication/reshape.rs @@ -1,15 +1,46 @@ +use crate::tests_utils::*; use rstsr::prelude::*; use super::CATEGORY; use crate::TESTCFG; +mod numpy_reshape { + use super::*; + static FUNC: &str = "numpy_reshape"; + + #[test] + fn multiarray_methods_reshape() { + // NumPy v2.4.2, _core/tests/test_multiarray.py, TestMethods::test_reshape + crate::specify_test!("multiarray_methods_reshape"); + + let mut device = TESTCFG.device.clone(); + device.set_default_order(RowMajor); + let arr = rt::tensor_from_nested!([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]], &device); + + let tgt = rt::tensor_from_nested!([[1, 2, 3, 4, 5, 6], [7, 8, 9, 10, 11, 12]], &device); + assert_equal(arr.reshape([2, 6]), &tgt, None); + + let tgt = rt::tensor_from_nested!([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], &device); + assert_equal(arr.reshape([3, 4]), &tgt, None); + + let tgt = rt::tensor_from_nested!([[1, 10, 8, 6], [4, 2, 11, 9], [7, 5, 3, 12]], &device); + let mut arr_col = arr.to_owned(); + arr_col.device_mut().set_default_order(ColMajor); + let mut arr_col = arr_col.into_shape([3, 4]).into_owned(); + arr_col.device_mut().set_default_order(RowMajor); + assert_equal(arr_col, &tgt, None); + + let tgt = rt::tensor_from_nested!([[1, 4, 7, 10], [2, 5, 8, 11], [3, 6, 9, 12]], &device); + assert_equal(arr.t().reshape([3, 4]), &tgt, None); + } +} + #[cfg(test)] mod docs_reshape { use super::*; static FUNC: &str = "docs_reshape"; #[test] - #[rustfmt::skip] fn quick_start() { crate::specify_test!("quick_start"); @@ -18,16 +49,12 @@ mod docs_reshape { let a = rt::arange((6, &device)); let a_reshaped = a.reshape([2, 3]); - let a_expected = rt::tensor_from_nested!( - [[0, 1, 2], [3, 4, 5]], - &device); + let a_expected = rt::tensor_from_nested!([[0, 1, 2], [3, 4, 5]], &device); assert!(rt::allclose(&a_reshaped, &a_expected, None)); // in this case, unspecified axes length is inferred as 6 / 3 = 2 let a_reshaped = a.reshape([3, -1]); - let a_expected = rt::tensor_from_nested!( - [[0, 1], [2, 3], [4, 5]], - &device); + let a_expected = rt::tensor_from_nested!([[0, 1], [2, 3], [4, 5]], &device); assert!(rt::allclose(&a_reshaped, &a_expected, None)); } diff --git a/rstsr-core/tests/tests_utils/equality.rs b/rstsr-core/tests/tests_utils/equality.rs new file mode 100644 index 0000000..1e40b5f --- /dev/null +++ b/rstsr-core/tests/tests_utils/equality.rs @@ -0,0 +1,27 @@ +use std::fmt::Debug; + +use rstsr::prelude::*; +use rstsr_core::storage::OpAllCloseAPI; +use rstsr_dtype_traits::IsCloseArgs; + +/// Raises an AssertionError if two objects are not equal. +/// +/// This function is similar to `np.testing.assert_equal`, but uses `rt::allclose` for value +/// comparison. This function does not have the same behavior on `NaN` values. Please fill +/// `isclose_arg = IsCloseArgs { equal_nan: true, ..Default::default() }` to make `NaN` values +/// compare equal. +pub fn assert_equal( + a: impl TensorViewAPI, + b: impl TensorViewAPI, + isclose_arg: impl Into>, +) where + TA: Clone + Debug, + TB: Clone + Debug, + B: DeviceAPI + DeviceAPI + OpAllCloseAPI + Debug, + DA: DimAPI, + DB: DimAPI, +{ + let (a, b) = (a.view().into_dim::(), b.view().into_dim::()); + assert_eq!(a.shape(), b.shape(), "Shape mismatch: {:?} vs {:?}", a.shape(), b.shape()); + assert!(rt::allclose(&a, &b, isclose_arg.into()), "Value mismatch: {:?} vs {:?}", a, b); +} diff --git a/rstsr-core/tests/tests_utils/mod.rs b/rstsr-core/tests/tests_utils/mod.rs index 42c4549..9e6b544 100644 --- a/rstsr-core/tests/tests_utils/mod.rs +++ b/rstsr-core/tests/tests_utils/mod.rs @@ -1,5 +1,9 @@ //! Utilities of tests. +pub mod equality; + +pub use equality::*; + /// Test configuration. pub struct TestCfg { /// Device instance (commonly used) to run the test on. From 80aa61fbcd922582088bb1ba405671f638f052bd Mon Sep 17 00:00:00 2001 From: ajz34 Date: Wed, 25 Feb 2026 16:51:49 +0800 Subject: [PATCH 4/5] core -- remove benches --- rstsr-core/benches/faer_gemm.rs | 20 ---- rstsr-core/benches/main.rs | 7 -- rstsr-core/benches/tensor_add.rs | 148 ------------------------- rstsr-core/benches/tensor_sum.rs | 180 ------------------------------- 4 files changed, 355 deletions(-) delete mode 100644 rstsr-core/benches/faer_gemm.rs delete mode 100644 rstsr-core/benches/main.rs delete mode 100644 rstsr-core/benches/tensor_add.rs delete mode 100644 rstsr-core/benches/tensor_sum.rs diff --git a/rstsr-core/benches/faer_gemm.rs b/rstsr-core/benches/faer_gemm.rs deleted file mode 100644 index 20729e1..0000000 --- a/rstsr-core/benches/faer_gemm.rs +++ /dev/null @@ -1,20 +0,0 @@ -use criterion::{black_box, criterion_group, Criterion}; -use rstsr_core::prelude_dev::*; -use std::time::Duration; - -pub fn bench_faer_gemm(crit: &mut Criterion) { - let m = 4096; - let n = 4096; - let k = 4096; - let device = DeviceFaer::default(); - let a = linspace((0.0, 1.0, m * k, &device)).into_shape_assume_contig([m, k]); - let b = linspace((0.0, 1.0, k * n, &device)).into_shape_assume_contig([k, n]); - crit.bench_function("gemm 4096", |ben| ben.iter(|| black_box(&a % &b))); - crit.bench_function("syrk 4096", |ben| ben.iter(|| black_box(&a % &a.reverse_axes()))); -} - -criterion_group! { - name = bench; - config = Criterion::default().warm_up_time(Duration::from_secs(1)).measurement_time(Duration::from_secs(10)); - targets = bench_faer_gemm -} diff --git a/rstsr-core/benches/main.rs b/rstsr-core/benches/main.rs deleted file mode 100644 index bd1e640..0000000 --- a/rstsr-core/benches/main.rs +++ /dev/null @@ -1,7 +0,0 @@ -use criterion::criterion_main; - -mod faer_gemm; -mod tensor_add; -mod tensor_sum; - -criterion_main!(tensor_sum::bench, tensor_add::bench, faer_gemm::bench); diff --git a/rstsr-core/benches/tensor_add.rs b/rstsr-core/benches/tensor_add.rs deleted file mode 100644 index 3b4e571..0000000 --- a/rstsr-core/benches/tensor_add.rs +++ /dev/null @@ -1,148 +0,0 @@ -use criterion::{black_box, criterion_group, Criterion}; -use rand::rngs::StdRng; -use rand::{Rng, SeedableRng}; -use std::time::Duration; - -fn rstsr_serial_4096(criterion: &mut Criterion) { - use rstsr_core::prelude::*; - - let n = 4096; - let mut rng = StdRng::seed_from_u64(42); - - let vec_a: Vec = (0..2 * n * 2 * n).map(|_| rng.gen()).collect::<_>(); - let vec_b: Vec = (0..2 * n * 2 * n).map(|_| rng.gen()).collect::<_>(); - let a_full = rt::asarray((vec_a, [2 * n, 2 * n], &DeviceCpuSerial::default())); - let b_full = rt::asarray((vec_b, [2 * n, 2 * n], &DeviceCpuSerial::default())); - - criterion.bench_function("rstsr serial add 8192 contiguous", |bencher| { - bencher.iter(|| { - let c = &a_full + &b_full; - black_box(c); - }) - }); - - let a = a_full.slice((..n, ..n)).into_dim::(); - let b = b_full.slice((..n, ..n)).into_dim::(); - - criterion.bench_function("rstsr serial add 4096 c-prefer", |bencher| { - bencher.iter(|| { - let c = &a + &b; - black_box(c); - }) - }); - - criterion.bench_function("rstsr serial add 4096 c-prefer transpose", |bencher| { - bencher.iter(|| { - let c = &a + &b.t(); - black_box(c); - }) - }); - - let a = a_full.i((slice!(0, 2 * n, 2), slice!(0, 2 * n, 2))).into_dim::(); - let b = b_full.i((slice!(0, 2 * n, 2), slice!(0, 2 * n, 2))).into_dim::(); - - criterion.bench_function("rstsr serial add 4096 strided", |bencher| { - bencher.iter(|| { - let c = &a + &b; - black_box(c); - }) - }); -} - -fn rstsr_rayon_4096(criterion: &mut Criterion) { - use rstsr_core::prelude::*; - - let n = 4096; - let mut rng = StdRng::seed_from_u64(42); - - let vec_a: Vec = (0..2 * n * 2 * n).map(|_| rng.gen()).collect::<_>(); - let vec_b: Vec = (0..2 * n * 2 * n).map(|_| rng.gen()).collect::<_>(); - let a_full = rt::asarray((vec_a, [2 * n, 2 * n])); - let b_full = rt::asarray((vec_b, [2 * n, 2 * n])); - - let a = a_full.slice((..n, ..n)).into_dim::(); - let b = b_full.slice((..n, ..n)).into_dim::(); - - criterion.bench_function("rstsr rayon add 8192 contiguous", |bencher| { - bencher.iter(|| { - let c = &a_full + &b_full; - black_box(c); - }) - }); - - criterion.bench_function("rstsr rayon add 4096 c-prefer", |bencher| { - bencher.iter(|| { - let c = &a + &b; - black_box(c); - }) - }); - - criterion.bench_function("rstsr rayon add 4096 c-prefer transpose", |bencher| { - bencher.iter(|| { - let c = &a + &b.t(); - black_box(c); - }) - }); - - let a = a_full.i((slice!(0, 2 * n, 2), slice!(0, 2 * n, 2))).into_dim::(); - let b = b_full.i((slice!(0, 2 * n, 2), slice!(0, 2 * n, 2))).into_dim::(); - - criterion.bench_function("rstsr rayon add 4096 strided", |bencher| { - bencher.iter(|| { - let c = &a + &b; - black_box(c); - }) - }); -} - -fn ndarray_4096(criterion: &mut Criterion) { - use ndarray::prelude::*; - - let n = 4096; - let mut rng = StdRng::seed_from_u64(42); - - let vec_a: Vec = (0..2 * n * 2 * n).map(|_| rng.gen()).collect::<_>(); - let vec_b: Vec = (0..2 * n * 2 * n).map(|_| rng.gen()).collect::<_>(); - let a_full = Array2::from_shape_vec((2 * n, 2 * n), vec_a).unwrap(); - let b_full = Array2::from_shape_vec((2 * n, 2 * n), vec_b).unwrap(); - - let a = a_full.slice(s![0..n, 0..n]); - let b = b_full.slice(s![0..n, 0..n]); - - criterion.bench_function("ndarray add 8192 contiguous", |bencher| { - bencher.iter(|| { - let c = &a_full + &b_full; - black_box(c); - }) - }); - - criterion.bench_function("ndarray add 4096 c-prefer", |bencher| { - bencher.iter(|| { - let c = &a + &b; - black_box(c); - }) - }); - - criterion.bench_function("ndarray add 4096 c-prefer transpose", |bencher| { - bencher.iter(|| { - let c = &a + &b.t(); - black_box(c); - }) - }); - - let a = a_full.slice(s![0..2 * n;2, 0..2 * n;2]); - let b = b_full.slice(s![0..2 * n;2, 0..2 * n;2]); - - criterion.bench_function("ndarray add 4096 strided", |bencher| { - bencher.iter(|| { - let c = &a + &b; - black_box(c); - }) - }); -} - -criterion_group! { - name = bench; - config = Criterion::default().warm_up_time(Duration::from_millis(200)).measurement_time(Duration::from_millis(2000)).sample_size(10); - targets = rstsr_serial_4096, rstsr_rayon_4096, ndarray_4096 -} diff --git a/rstsr-core/benches/tensor_sum.rs b/rstsr-core/benches/tensor_sum.rs deleted file mode 100644 index 95e3928..0000000 --- a/rstsr-core/benches/tensor_sum.rs +++ /dev/null @@ -1,180 +0,0 @@ -use criterion::{black_box, criterion_group, Criterion}; -use rand::rngs::StdRng; -use rand::{Rng, SeedableRng}; -use std::time::Duration; - -fn rstsr_serial_4096(criterion: &mut Criterion) { - use rstsr_core::prelude::*; - - let n = 4096; - let mut rng = StdRng::seed_from_u64(42); - - let vec_a: Vec = (0..n * n).map(|_| rng.gen()).collect::<_>(); - let a = rt::asarray((vec_a, [n, n], &DeviceCpuSerial::default())); - - criterion.bench_function("rstsr serial simple sum 4096", |bencher| { - bencher.iter(|| { - let c = a.sum_all(); - black_box(c); - }) - }); - - let vec_b: Vec = (0..4 * n * n).map(|_| rng.gen()).collect::<_>(); - let b_full = rt::asarray((vec_b, [2 * n, 2 * n], &DeviceCpuSerial::default())); - - // contiguous slice - let b = b_full.slice([0..n, 0..n]); - criterion.bench_function("rstsr serial simple sum 4096 slice", |bencher| { - bencher.iter(|| { - let c = b.sum_all(); - black_box(c); - }) - }); - - // strided - let b = b_full.slice([slice!(0, 2 * n, 2), slice!(0, 2 * n, 2)]); - criterion.bench_function("rstsr serial simple sum 4096 strided", |bencher| { - bencher.iter(|| { - let c = b.sum_all(); - black_box(c); - }) - }); - - // add leading dimension - let b = b_full.reshape([4, n, n]); - criterion.bench_function("rstsr serial simple sum 4096 leading dimension", |bencher| { - bencher.iter(|| { - // let c = b.i(0) + b.i(1) + b.i(2) + b.i(3); - let c = b.sum_axes(0); - black_box(c); - }) - }); - - // add last dimension - let b = b_full.reshape([4, n, n]); - criterion.bench_function("rstsr serial simple sum 4096 last dimension", |bencher| { - bencher.iter(|| { - let c = b.sum_axes([-1, -2]); - black_box(c); - }) - }); -} - -fn rstsr_rayon_4096(criterion: &mut Criterion) { - use rstsr_core::prelude::*; - - let n = 4096; - let mut rng = StdRng::seed_from_u64(42); - - let vec_a: Vec = (0..n * n).map(|_| rng.gen()).collect::<_>(); - let a = rt::asarray((vec_a, [n, n])); - - criterion.bench_function("rstsr rayon simple sum 4096", |bencher| { - bencher.iter(|| { - let c = a.sum_all(); - black_box(c); - }) - }); - - let vec_b: Vec = (0..4 * n * n).map(|_| rng.gen()).collect::<_>(); - let b_full = rt::asarray((vec_b, [2 * n, 2 * n])); - - // contiguous slice - let b = b_full.slice([0..n, 0..n]); - criterion.bench_function("rstsr rayon simple sum 4096 slice", |bencher| { - bencher.iter(|| { - let c = b.sum_all(); - black_box(c); - }) - }); - - // strided - let b = b_full.slice([slice!(0, 2 * n, 2), slice!(0, 2 * n, 2)]); - criterion.bench_function("rstsr rayon simple sum 4096 strided", |bencher| { - bencher.iter(|| { - let c = b.sum_all(); - black_box(c); - }) - }); - - // add leading dimension - let b = b_full.reshape([4, n, n]); - criterion.bench_function("rstsr rayon simple sum 4096 leading dimension", |bencher| { - bencher.iter(|| { - // let c = b.i(0) + b.i(1) + b.i(2) + b.i(3); - let c = b.sum_axes(0); - black_box(c); - }) - }); - - // add last dimension - let b = b_full.reshape([4, n, n]); - criterion.bench_function("rstsr serial simple sum 4096 last dimension", |bencher| { - bencher.iter(|| { - let c = b.sum_axes([-1, -2]); - black_box(c); - }) - }); -} - -fn ndarray_4096(criterion: &mut Criterion) { - use ndarray::prelude::*; - - let n = 4096; - let mut rng = StdRng::seed_from_u64(42); - - let vec_a: Vec = (0..n * n).map(|_| rng.gen()).collect::<_>(); - let a = Array2::from_shape_vec((n, n).f(), vec_a).unwrap(); - - criterion.bench_function("ndarray simple sum 4096", |bencher| { - bencher.iter(|| { - let c = a.sum(); - black_box(c); - }) - }); - - let vec_b: Vec = (0..4 * n * n).map(|_| rng.gen()).collect::<_>(); - let b_full = Array2::from_shape_vec((2 * n, 2 * n), vec_b).unwrap(); - - // contiguous slice - let b = b_full.slice(s![..n, ..n]); - criterion.bench_function("ndarray simple sum 4096 slice", |bencher| { - bencher.iter(|| { - let c = b.sum(); - black_box(c); - }) - }); - - // strided - let b = b_full.slice(s![..;2, ..;2]); - criterion.bench_function("ndarray simple sum 4096 strided", |bencher| { - bencher.iter(|| { - let c = b.sum(); - black_box(c); - }) - }); - - // add leading dimension - let b = b_full.to_shape((4, n, n)).unwrap(); - criterion.bench_function("ndarray simple sum 4096 leading dimension", |bencher| { - bencher.iter(|| { - let c = b.sum_axis(Axis(0)); - black_box(c); - }) - }); - - // add last dimension - let b = b_full.to_shape((4, n * n)).unwrap(); - criterion.bench_function("ndarray simple sum 4096 last dimension", |bencher| { - bencher.iter(|| { - let c = b.sum_axis(Axis(1)); - black_box(c); - }) - }); -} - -criterion_group! { - name = bench; - config = Criterion::default().warm_up_time(Duration::from_millis(200)).measurement_time(Duration::from_millis(2000)).sample_size(10); - targets = rstsr_serial_4096, rstsr_rayon_4096, ndarray_4096 -} From d778d9ceb83a7f2130a40495f63c8cce3e32a628 Mon Sep 17 00:00:00 2001 From: ajz34 Date: Wed, 25 Feb 2026 17:00:27 +0800 Subject: [PATCH 5/5] fix test --- rstsr-core/Cargo.toml | 4 ---- rstsr-core/src/tensor/manuplication/into_dim.rs | 2 +- rstsr-core/src/tensor/manuplication/reshape.rs | 4 +++- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/rstsr-core/Cargo.toml b/rstsr-core/Cargo.toml index df75941..ce4bcf1 100644 --- a/rstsr-core/Cargo.toml +++ b/rstsr-core/Cargo.toml @@ -58,10 +58,6 @@ aligned_alloc = ["rstsr-common/aligned_alloc"] # And more importantly, this feature will hugely increase compile time. dispatch_dim_layout_iter = ["rstsr-common/dispatch_dim_layout_iter"] -[[bench]] -name = "main" -harness = false - [package.metadata.docs.rs] features = ["default"] rustdoc-args = ["--cfg", "docsrs", "--document-private-items", "--html-in-header", "katex-header.html"] diff --git a/rstsr-core/src/tensor/manuplication/into_dim.rs b/rstsr-core/src/tensor/manuplication/into_dim.rs index da965ac..5f3eb26 100644 --- a/rstsr-core/src/tensor/manuplication/into_dim.rs +++ b/rstsr-core/src/tensor/manuplication/into_dim.rs @@ -86,7 +86,7 @@ where /// /// - The shape of the tensor is not compatible with the target dimension type. /// -/// ```rust +/// ```rust,should_panic /// use rstsr::prelude::*; /// let a = rt::arange(6).into_shape([2, 3]); // shape: (2, 3), IxD /// let b = a.to_dim::(); // shape: (2, 3), Ix3, panics diff --git a/rstsr-core/src/tensor/manuplication/reshape.rs b/rstsr-core/src/tensor/manuplication/reshape.rs index 50f7e2f..28747a3 100644 --- a/rstsr-core/src/tensor/manuplication/reshape.rs +++ b/rstsr-core/src/tensor/manuplication/reshape.rs @@ -340,6 +340,7 @@ where /// # device.set_default_order(RowMajor); /// # /// // in this case, unspecified axes length is inferred as 6 / 3 = 2 +/// let a = rt::arange((6, &device)); /// let a_reshaped = a.reshape([3, -1]); /// let a_expected = rt::tensor_from_nested!( /// [[0, 1], [2, 3], [4, 5]], @@ -368,11 +369,12 @@ where /// /// You may encounter ownership problem when you try to assign a reshaped tensor like this: /// -/// ```rust,should_panic +/// ```rust,compile_fail /// # use rstsr::prelude::*; /// # let mut device = DeviceCpu::default(); /// # device.set_default_order(RowMajor); /// let a = rt::arange((6, &device)).reshape([2, 3]); +/// println!("a: {:?}", a); /// ``` /// /// The compiler may give an error like: