array-api-strict 2.2__py3-none-any.whl → 2.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- array_api_strict/__init__.py +10 -7
- array_api_strict/_array_object.py +31 -19
- array_api_strict/_creation_functions.py +2 -0
- array_api_strict/_data_type_functions.py +34 -3
- array_api_strict/_dtypes.py +1 -0
- array_api_strict/_elementwise_functions.py +140 -471
- array_api_strict/_fft.py +31 -5
- array_api_strict/_flags.py +10 -8
- array_api_strict/_helpers.py +37 -0
- array_api_strict/_linear_algebra_functions.py +1 -1
- array_api_strict/_manipulation_functions.py +5 -0
- array_api_strict/_searching_functions.py +44 -5
- array_api_strict/_statistical_functions.py +42 -5
- array_api_strict/_version.py +16 -16
- array_api_strict/tests/test_array_object.py +146 -74
- array_api_strict/tests/test_creation_functions.py +7 -0
- array_api_strict/tests/test_data_type_functions.py +24 -4
- array_api_strict/tests/test_elementwise_functions.py +66 -8
- array_api_strict/tests/test_flags.py +29 -18
- array_api_strict/tests/test_manipulation_functions.py +1 -1
- array_api_strict/tests/test_searching_functions.py +24 -0
- array_api_strict/tests/test_statistical_functions.py +19 -1
- array_api_strict/tests/test_validation.py +1 -1
- array_api_strict-2.3.dist-info/METADATA +68 -0
- array_api_strict-2.3.dist-info/RECORD +43 -0
- {array_api_strict-2.2.dist-info → array_api_strict-2.3.dist-info}/WHEEL +1 -1
- array_api_strict-2.2.dist-info/METADATA +0 -37
- array_api_strict-2.2.dist-info/RECORD +0 -41
- {array_api_strict-2.2.dist-info → array_api_strict-2.3.dist-info}/LICENSE +0 -0
- {array_api_strict-2.2.dist-info → array_api_strict-2.3.dist-info}/top_level.txt +0 -0
array_api_strict/_fft.py
CHANGED
|
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
|
|
|
4
4
|
|
|
5
5
|
if TYPE_CHECKING:
|
|
6
6
|
from typing import Union, Optional, Literal
|
|
7
|
-
from ._typing import Device
|
|
7
|
+
from ._typing import Device, Dtype as DType
|
|
8
8
|
from collections.abc import Sequence
|
|
9
9
|
|
|
10
10
|
from ._dtypes import (
|
|
@@ -251,7 +251,14 @@ def ihfft(
|
|
|
251
251
|
return res
|
|
252
252
|
|
|
253
253
|
@requires_extension('fft')
|
|
254
|
-
def fftfreq(
|
|
254
|
+
def fftfreq(
|
|
255
|
+
n: int,
|
|
256
|
+
/,
|
|
257
|
+
*,
|
|
258
|
+
d: float = 1.0,
|
|
259
|
+
dtype: Optional[DType] = None,
|
|
260
|
+
device: Optional[Device] = None
|
|
261
|
+
) -> Array:
|
|
255
262
|
"""
|
|
256
263
|
Array API compatible wrapper for :py:func:`np.fft.fftfreq <numpy.fft.fftfreq>`.
|
|
257
264
|
|
|
@@ -259,10 +266,23 @@ def fftfreq(n: int, /, *, d: float = 1.0, device: Optional[Device] = None) -> Ar
|
|
|
259
266
|
"""
|
|
260
267
|
if device is not None and device not in ALL_DEVICES:
|
|
261
268
|
raise ValueError(f"Unsupported device {device!r}")
|
|
262
|
-
|
|
269
|
+
if dtype and not dtype in _real_floating_dtypes:
|
|
270
|
+
raise ValueError(f"`dtype` must be a real floating-point type. Got {dtype=}.")
|
|
271
|
+
|
|
272
|
+
np_result = np.fft.fftfreq(n, d=d)
|
|
273
|
+
if dtype:
|
|
274
|
+
np_result = np_result.astype(dtype._np_dtype)
|
|
275
|
+
return Array._new(np_result, device=device)
|
|
263
276
|
|
|
264
277
|
@requires_extension('fft')
|
|
265
|
-
def rfftfreq(
|
|
278
|
+
def rfftfreq(
|
|
279
|
+
n: int,
|
|
280
|
+
/,
|
|
281
|
+
*,
|
|
282
|
+
d: float = 1.0,
|
|
283
|
+
dtype: Optional[DType] = None,
|
|
284
|
+
device: Optional[Device] = None
|
|
285
|
+
) -> Array:
|
|
266
286
|
"""
|
|
267
287
|
Array API compatible wrapper for :py:func:`np.fft.rfftfreq <numpy.fft.rfftfreq>`.
|
|
268
288
|
|
|
@@ -270,7 +290,13 @@ def rfftfreq(n: int, /, *, d: float = 1.0, device: Optional[Device] = None) -> A
|
|
|
270
290
|
"""
|
|
271
291
|
if device is not None and device not in ALL_DEVICES:
|
|
272
292
|
raise ValueError(f"Unsupported device {device!r}")
|
|
273
|
-
|
|
293
|
+
if dtype and not dtype in _real_floating_dtypes:
|
|
294
|
+
raise ValueError(f"`dtype` must be a real floating-point type. Got {dtype=}.")
|
|
295
|
+
|
|
296
|
+
np_result = np.fft.rfftfreq(n, d=d)
|
|
297
|
+
if dtype:
|
|
298
|
+
np_result = np_result.astype(dtype._np_dtype)
|
|
299
|
+
return Array._new(np_result, device=device)
|
|
274
300
|
|
|
275
301
|
@requires_extension('fft')
|
|
276
302
|
def fftshift(x: Array, /, *, axes: Union[int, Sequence[int]] = None) -> Array:
|
array_api_strict/_flags.py
CHANGED
|
@@ -22,11 +22,12 @@ supported_versions = (
|
|
|
22
22
|
"2021.12",
|
|
23
23
|
"2022.12",
|
|
24
24
|
"2023.12",
|
|
25
|
+
"2024.12"
|
|
25
26
|
)
|
|
26
27
|
|
|
27
|
-
draft_version = "
|
|
28
|
+
draft_version = "2025.12"
|
|
28
29
|
|
|
29
|
-
API_VERSION = default_version = "
|
|
30
|
+
API_VERSION = default_version = "2024.12"
|
|
30
31
|
|
|
31
32
|
BOOLEAN_INDEXING = True
|
|
32
33
|
|
|
@@ -169,12 +170,13 @@ def set_array_api_strict_flags(
|
|
|
169
170
|
set(default_extensions))
|
|
170
171
|
|
|
171
172
|
# We have to do this separately or it won't get added as the docstring
|
|
172
|
-
set_array_api_strict_flags.__doc__
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
173
|
+
if set_array_api_strict_flags.__doc__ is not None:
|
|
174
|
+
set_array_api_strict_flags.__doc__ = set_array_api_strict_flags.__doc__.format(
|
|
175
|
+
supported_versions=supported_versions,
|
|
176
|
+
default_version=default_version,
|
|
177
|
+
default_extensions=default_extensions,
|
|
178
|
+
draft_version=draft_version,
|
|
179
|
+
)
|
|
178
180
|
|
|
179
181
|
def get_array_api_strict_flags():
|
|
180
182
|
"""
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Private helper routines.
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
from ._flags import get_array_api_strict_flags
|
|
5
|
+
from ._dtypes import _dtype_categories
|
|
6
|
+
|
|
7
|
+
_py_scalars = (bool, int, float, complex)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def _maybe_normalize_py_scalars(x1, x2, dtype_category, func_name):
|
|
11
|
+
|
|
12
|
+
flags = get_array_api_strict_flags()
|
|
13
|
+
if flags["api_version"] < "2024.12":
|
|
14
|
+
# scalars will fail at the call site
|
|
15
|
+
return x1, x2
|
|
16
|
+
|
|
17
|
+
_allowed_dtypes = _dtype_categories[dtype_category]
|
|
18
|
+
|
|
19
|
+
if isinstance(x1, _py_scalars):
|
|
20
|
+
if isinstance(x2, _py_scalars):
|
|
21
|
+
raise TypeError(f"Two scalars not allowed, got {type(x1) = } and {type(x2) =}")
|
|
22
|
+
# x2 must be an array
|
|
23
|
+
if x2.dtype not in _allowed_dtypes:
|
|
24
|
+
raise TypeError(f"Only {dtype_category} dtypes are allowed {func_name}. Got {x2.dtype}.")
|
|
25
|
+
x1 = x2._promote_scalar(x1)
|
|
26
|
+
|
|
27
|
+
elif isinstance(x2, _py_scalars):
|
|
28
|
+
# x1 must be an array
|
|
29
|
+
if x1.dtype not in _allowed_dtypes:
|
|
30
|
+
raise TypeError(f"Only {dtype_category} dtypes are allowed {func_name}. Got {x1.dtype}.")
|
|
31
|
+
x2 = x1._promote_scalar(x2)
|
|
32
|
+
else:
|
|
33
|
+
if x1.dtype not in _allowed_dtypes or x2.dtype not in _allowed_dtypes:
|
|
34
|
+
raise TypeError(f"Only {dtype_category} dtypes are allowed {func_name}. "
|
|
35
|
+
f"Got {x1.dtype} and {x2.dtype}.")
|
|
36
|
+
return x1, x2
|
|
37
|
+
|
|
@@ -86,5 +86,5 @@ def vecdot(x1: Array, x2: Array, /, *, axis: int = -1) -> Array:
|
|
|
86
86
|
x1_ = np.moveaxis(x1_, axis, -1)
|
|
87
87
|
x2_ = np.moveaxis(x2_, axis, -1)
|
|
88
88
|
|
|
89
|
-
res = x1_[..., None, :] @ x2_[..., None]
|
|
89
|
+
res = np.conj(x1_[..., None, :]) @ x2_[..., None]
|
|
90
90
|
return Array._new(res[..., 0, 0], device=x1.device)
|
|
@@ -153,6 +153,11 @@ def squeeze(x: Array, /, axis: Union[int, Tuple[int, ...]]) -> Array:
|
|
|
153
153
|
|
|
154
154
|
See its docstring for more information.
|
|
155
155
|
"""
|
|
156
|
+
if axis is None:
|
|
157
|
+
raise ValueError(
|
|
158
|
+
"squeeze(..., axis=None is not supported. See "
|
|
159
|
+
"https://github.com/data-apis/array-api/pull/100 for a discussion."
|
|
160
|
+
)
|
|
156
161
|
return Array._new(np.squeeze(x._array, axis=axis), device=x.device)
|
|
157
162
|
|
|
158
163
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from ._array_object import Array
|
|
4
|
-
from ._dtypes import _result_type, _real_numeric_dtypes
|
|
5
|
-
from ._flags import requires_data_dependent_shapes, requires_api_version
|
|
4
|
+
from ._dtypes import _result_type, _real_numeric_dtypes, bool as _bool
|
|
5
|
+
from ._flags import requires_data_dependent_shapes, requires_api_version, get_array_api_strict_flags
|
|
6
6
|
|
|
7
7
|
from typing import TYPE_CHECKING
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
|
-
from typing import Literal, Optional, Tuple
|
|
9
|
+
from typing import Literal, Optional, Tuple, Union
|
|
10
10
|
|
|
11
11
|
import numpy as np
|
|
12
12
|
|
|
@@ -45,6 +45,24 @@ def nonzero(x: Array, /) -> Tuple[Array, ...]:
|
|
|
45
45
|
raise ValueError("nonzero is not allowed on 0-dimensional arrays")
|
|
46
46
|
return tuple(Array._new(i, device=x.device) for i in np.nonzero(x._array))
|
|
47
47
|
|
|
48
|
+
|
|
49
|
+
@requires_api_version('2024.12')
|
|
50
|
+
def count_nonzero(
|
|
51
|
+
x: Array,
|
|
52
|
+
/,
|
|
53
|
+
*,
|
|
54
|
+
axis: Optional[Union[int, Tuple[int, ...]]] = None,
|
|
55
|
+
keepdims: bool = False,
|
|
56
|
+
) -> Array:
|
|
57
|
+
"""
|
|
58
|
+
Array API compatible wrapper for :py:func:`np.count_nonzero <numpy.count_nonzero>`
|
|
59
|
+
|
|
60
|
+
See its docstring for more information.
|
|
61
|
+
"""
|
|
62
|
+
arr = np.count_nonzero(x._array, axis=axis, keepdims=keepdims)
|
|
63
|
+
return Array._new(np.asarray(arr), device=x.device)
|
|
64
|
+
|
|
65
|
+
|
|
48
66
|
@requires_api_version('2023.12')
|
|
49
67
|
def searchsorted(
|
|
50
68
|
x1: Array,
|
|
@@ -72,17 +90,38 @@ def searchsorted(
|
|
|
72
90
|
# x1 must be 1-D, but NumPy already requires this.
|
|
73
91
|
return Array._new(np.searchsorted(x1._array, x2._array, side=side, sorter=sorter), device=x1.device)
|
|
74
92
|
|
|
75
|
-
def where(
|
|
93
|
+
def where(
|
|
94
|
+
condition: Array,
|
|
95
|
+
x1: bool | int | float | complex | Array,
|
|
96
|
+
x2: bool | int | float | complex | Array, /
|
|
97
|
+
) -> Array:
|
|
76
98
|
"""
|
|
77
99
|
Array API compatible wrapper for :py:func:`np.where <numpy.where>`.
|
|
78
100
|
|
|
79
101
|
See its docstring for more information.
|
|
80
102
|
"""
|
|
103
|
+
if get_array_api_strict_flags()['api_version'] > '2023.12':
|
|
104
|
+
num_scalars = 0
|
|
105
|
+
|
|
106
|
+
if isinstance(x1, (bool, float, complex, int)):
|
|
107
|
+
x1 = Array._new(np.asarray(x1), device=condition.device)
|
|
108
|
+
num_scalars += 1
|
|
109
|
+
|
|
110
|
+
if isinstance(x2, (bool, float, complex, int)):
|
|
111
|
+
x2 = Array._new(np.asarray(x2), device=condition.device)
|
|
112
|
+
num_scalars += 1
|
|
113
|
+
|
|
114
|
+
if num_scalars == 2:
|
|
115
|
+
raise ValueError("One of x1, x2 arguments must be an array.")
|
|
116
|
+
|
|
81
117
|
# Call result type here just to raise on disallowed type combinations
|
|
82
118
|
_result_type(x1.dtype, x2.dtype)
|
|
119
|
+
|
|
120
|
+
if condition.dtype != _bool:
|
|
121
|
+
raise TypeError("`condition` must be have a boolean data type")
|
|
83
122
|
|
|
84
123
|
if len({a.device for a in (condition, x1, x2)}) > 1:
|
|
85
|
-
raise ValueError("where
|
|
124
|
+
raise ValueError("Inputs to `where` must all use the same device")
|
|
86
125
|
|
|
87
126
|
x1, x2 = Array._normalize_two_args(x1, x2)
|
|
88
127
|
return Array._new(np.where(condition._array, x1._array, x2._array), device=x1.device)
|
|
@@ -3,12 +3,13 @@ from __future__ import annotations
|
|
|
3
3
|
from ._dtypes import (
|
|
4
4
|
_real_floating_dtypes,
|
|
5
5
|
_real_numeric_dtypes,
|
|
6
|
+
_floating_dtypes,
|
|
6
7
|
_numeric_dtypes,
|
|
7
8
|
)
|
|
8
9
|
from ._array_object import Array
|
|
9
10
|
from ._dtypes import float32, complex64
|
|
10
11
|
from ._flags import requires_api_version, get_array_api_strict_flags
|
|
11
|
-
from ._creation_functions import zeros
|
|
12
|
+
from ._creation_functions import zeros, ones
|
|
12
13
|
from ._manipulation_functions import concat
|
|
13
14
|
|
|
14
15
|
from typing import TYPE_CHECKING
|
|
@@ -30,7 +31,6 @@ def cumulative_sum(
|
|
|
30
31
|
) -> Array:
|
|
31
32
|
if x.dtype not in _numeric_dtypes:
|
|
32
33
|
raise TypeError("Only numeric dtypes are allowed in cumulative_sum")
|
|
33
|
-
dt = x.dtype if dtype is None else dtype
|
|
34
34
|
if dtype is not None:
|
|
35
35
|
dtype = dtype._np_dtype
|
|
36
36
|
|
|
@@ -43,9 +43,40 @@ def cumulative_sum(
|
|
|
43
43
|
if include_initial:
|
|
44
44
|
if axis < 0:
|
|
45
45
|
axis += x.ndim
|
|
46
|
-
x = concat([zeros(x.shape[:axis] + (1,) + x.shape[axis + 1:], dtype=
|
|
46
|
+
x = concat([zeros(x.shape[:axis] + (1,) + x.shape[axis + 1:], dtype=x.dtype), x], axis=axis)
|
|
47
47
|
return Array._new(np.cumsum(x._array, axis=axis, dtype=dtype), device=x.device)
|
|
48
48
|
|
|
49
|
+
|
|
50
|
+
@requires_api_version('2024.12')
|
|
51
|
+
def cumulative_prod(
|
|
52
|
+
x: Array,
|
|
53
|
+
/,
|
|
54
|
+
*,
|
|
55
|
+
axis: Optional[int] = None,
|
|
56
|
+
dtype: Optional[Dtype] = None,
|
|
57
|
+
include_initial: bool = False,
|
|
58
|
+
) -> Array:
|
|
59
|
+
if x.dtype not in _numeric_dtypes:
|
|
60
|
+
raise TypeError("Only numeric dtypes are allowed in cumulative_prod")
|
|
61
|
+
if x.ndim == 0:
|
|
62
|
+
raise ValueError("Only ndim >= 1 arrays are allowed in cumulative_prod")
|
|
63
|
+
|
|
64
|
+
if dtype is not None:
|
|
65
|
+
dtype = dtype._np_dtype
|
|
66
|
+
|
|
67
|
+
if axis is None:
|
|
68
|
+
if x.ndim > 1:
|
|
69
|
+
raise ValueError("axis must be specified in cumulative_prod for more than one dimension")
|
|
70
|
+
axis = 0
|
|
71
|
+
|
|
72
|
+
# np.cumprod does not support include_initial
|
|
73
|
+
if include_initial:
|
|
74
|
+
if axis < 0:
|
|
75
|
+
axis += x.ndim
|
|
76
|
+
x = concat([ones(x.shape[:axis] + (1,) + x.shape[axis + 1:], dtype=x.dtype), x], axis=axis)
|
|
77
|
+
return Array._new(np.cumprod(x._array, axis=axis, dtype=dtype), device=x.device)
|
|
78
|
+
|
|
79
|
+
|
|
49
80
|
def max(
|
|
50
81
|
x: Array,
|
|
51
82
|
/,
|
|
@@ -65,8 +96,14 @@ def mean(
|
|
|
65
96
|
axis: Optional[Union[int, Tuple[int, ...]]] = None,
|
|
66
97
|
keepdims: bool = False,
|
|
67
98
|
) -> Array:
|
|
68
|
-
|
|
69
|
-
|
|
99
|
+
|
|
100
|
+
if get_array_api_strict_flags()['api_version'] > '2023.12':
|
|
101
|
+
allowed_dtypes = _floating_dtypes
|
|
102
|
+
else:
|
|
103
|
+
allowed_dtypes = _real_floating_dtypes
|
|
104
|
+
|
|
105
|
+
if x.dtype not in allowed_dtypes:
|
|
106
|
+
raise TypeError("Only floating-point dtypes are allowed in mean")
|
|
70
107
|
return Array._new(np.mean(x._array, axis=axis, keepdims=keepdims), device=x.device)
|
|
71
108
|
|
|
72
109
|
|
array_api_strict/_version.py
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
+
# file generated by setuptools-scm
|
|
2
|
+
# don't change, don't track in version control
|
|
1
3
|
|
|
2
|
-
|
|
3
|
-
# revision-control system data, or from the parent directory name of an
|
|
4
|
-
# unpacked source archive. Distribution tarballs contain a pre-generated copy
|
|
5
|
-
# of this file.
|
|
4
|
+
__all__ = ["__version__", "__version_tuple__", "version", "version_tuple"]
|
|
6
5
|
|
|
7
|
-
|
|
6
|
+
TYPE_CHECKING = False
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from typing import Tuple
|
|
9
|
+
from typing import Union
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"dirty": false,
|
|
13
|
-
"error": null,
|
|
14
|
-
"full-revisionid": "fe4f34ad30ba59c1c981037dd181f6b4daf23b22",
|
|
15
|
-
"version": "2.2"
|
|
16
|
-
}
|
|
17
|
-
''' # END VERSION_JSON
|
|
11
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
12
|
+
else:
|
|
13
|
+
VERSION_TUPLE = object
|
|
18
14
|
|
|
15
|
+
version: str
|
|
16
|
+
__version__: str
|
|
17
|
+
__version_tuple__: VERSION_TUPLE
|
|
18
|
+
version_tuple: VERSION_TUPLE
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
__version__ = version = '2.3'
|
|
21
|
+
__version_tuple__ = version_tuple = (2, 3)
|