array-api-strict 2.3__py3-none-any.whl → 2.4__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 +11 -5
- array_api_strict/_array_object.py +226 -200
- array_api_strict/_constants.py +1 -1
- array_api_strict/_creation_functions.py +97 -119
- array_api_strict/_data_type_functions.py +73 -64
- array_api_strict/_dtypes.py +35 -24
- array_api_strict/_elementwise_functions.py +138 -482
- array_api_strict/_fft.py +28 -32
- array_api_strict/_flags.py +65 -26
- array_api_strict/_helpers.py +23 -14
- array_api_strict/_indexing_functions.py +3 -8
- array_api_strict/_info.py +64 -69
- array_api_strict/_linalg.py +57 -53
- array_api_strict/_linear_algebra_functions.py +11 -9
- array_api_strict/_manipulation_functions.py +30 -30
- array_api_strict/_searching_functions.py +22 -33
- array_api_strict/_set_functions.py +4 -6
- array_api_strict/_sorting_functions.py +6 -6
- array_api_strict/_statistical_functions.py +57 -64
- array_api_strict/_typing.py +30 -50
- array_api_strict/_utility_functions.py +11 -13
- array_api_strict/_version.py +2 -2
- array_api_strict/py.typed +0 -0
- array_api_strict/tests/test_array_object.py +163 -56
- array_api_strict/tests/test_creation_functions.py +14 -12
- array_api_strict/tests/test_data_type_functions.py +40 -6
- array_api_strict/tests/test_elementwise_functions.py +94 -45
- array_api_strict/tests/test_searching_functions.py +79 -1
- array_api_strict/tests/test_validation.py +1 -3
- {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/METADATA +5 -4
- array_api_strict-2.4.dist-info/RECORD +44 -0
- {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/WHEEL +1 -1
- array_api_strict-2.3.dist-info/RECORD +0 -43
- {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/LICENSE +0 -0
- {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/top_level.txt +0 -0
array_api_strict/_constants.py
CHANGED
|
@@ -1,51 +1,47 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
from typing import TYPE_CHECKING,
|
|
3
|
+
from enum import Enum
|
|
4
|
+
from typing import TYPE_CHECKING, Literal
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Device,
|
|
10
|
-
Dtype,
|
|
11
|
-
NestedSequence,
|
|
12
|
-
SupportsBufferProtocol,
|
|
13
|
-
)
|
|
14
|
-
from ._dtypes import _DType, _all_dtypes
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from ._dtypes import DType, _all_dtypes, _np_dtype
|
|
15
9
|
from ._flags import get_array_api_strict_flags
|
|
10
|
+
from ._typing import NestedSequence, SupportsBufferProtocol, SupportsDLPack
|
|
16
11
|
|
|
17
|
-
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
# TODO import from typing (requires Python >=3.13)
|
|
14
|
+
from typing_extensions import TypeIs
|
|
18
15
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"""
|
|
22
|
-
Temporarily enable Array.__array__. This is needed for np.array to parse
|
|
23
|
-
list of lists of Array objects.
|
|
24
|
-
"""
|
|
25
|
-
from . import _array_object
|
|
26
|
-
original_value = _array_object._allow_array
|
|
27
|
-
try:
|
|
28
|
-
_array_object._allow_array = True
|
|
29
|
-
yield
|
|
30
|
-
finally:
|
|
31
|
-
_array_object._allow_array = original_value
|
|
16
|
+
# Circular import
|
|
17
|
+
from ._array_object import Array, Device
|
|
32
18
|
|
|
33
|
-
|
|
19
|
+
|
|
20
|
+
class Undef(Enum):
|
|
21
|
+
UNDEF = 0
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_undef = Undef.UNDEF
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _check_valid_dtype(dtype: DType | None) -> None:
|
|
34
28
|
# Note: Only spelling dtypes as the dtype objects is supported.
|
|
35
29
|
if dtype not in (None,) + _all_dtypes:
|
|
36
30
|
raise ValueError(f"dtype must be one of the supported dtypes, got {dtype!r}")
|
|
37
31
|
|
|
38
|
-
|
|
32
|
+
|
|
33
|
+
def _supports_buffer_protocol(obj: object) -> TypeIs[SupportsBufferProtocol]:
|
|
39
34
|
try:
|
|
40
|
-
memoryview(obj)
|
|
35
|
+
memoryview(obj) # type: ignore[arg-type]
|
|
41
36
|
except TypeError:
|
|
42
37
|
return False
|
|
43
38
|
return True
|
|
44
39
|
|
|
45
|
-
|
|
40
|
+
|
|
41
|
+
def _check_device(device: Device | None) -> None:
|
|
46
42
|
# _array_object imports in this file are inside the functions to avoid
|
|
47
43
|
# circular imports
|
|
48
|
-
from ._array_object import
|
|
44
|
+
from ._array_object import ALL_DEVICES, Device
|
|
49
45
|
|
|
50
46
|
if device is not None and not isinstance(device, Device):
|
|
51
47
|
raise ValueError(f"Unsupported device {device!r}")
|
|
@@ -53,20 +49,14 @@ def _check_device(device):
|
|
|
53
49
|
if device is not None and device not in ALL_DEVICES:
|
|
54
50
|
raise ValueError(f"Unsupported device {device!r}")
|
|
55
51
|
|
|
52
|
+
|
|
56
53
|
def asarray(
|
|
57
|
-
obj:
|
|
58
|
-
Array,
|
|
59
|
-
bool,
|
|
60
|
-
int,
|
|
61
|
-
float,
|
|
62
|
-
NestedSequence[bool | int | float],
|
|
63
|
-
SupportsBufferProtocol,
|
|
64
|
-
],
|
|
54
|
+
obj: Array | complex | NestedSequence[complex] | SupportsBufferProtocol,
|
|
65
55
|
/,
|
|
66
56
|
*,
|
|
67
|
-
dtype:
|
|
68
|
-
device:
|
|
69
|
-
copy:
|
|
57
|
+
dtype: DType | None = None,
|
|
58
|
+
device: Device | None = None,
|
|
59
|
+
copy: bool | None = None,
|
|
70
60
|
) -> Array:
|
|
71
61
|
"""
|
|
72
62
|
Array API compatible wrapper for :py:func:`np.asarray <numpy.asarray>`.
|
|
@@ -108,23 +98,27 @@ def asarray(
|
|
|
108
98
|
|
|
109
99
|
if isinstance(obj, Array):
|
|
110
100
|
return Array._new(np.array(obj._array, copy=copy, dtype=_np_dtype), device=device)
|
|
101
|
+
elif isinstance(obj, list | tuple):
|
|
102
|
+
if any(isinstance(x, Array) for x in obj):
|
|
103
|
+
raise TypeError("Nested Arrays are not allowed. Use `stack` instead.")
|
|
104
|
+
|
|
111
105
|
if dtype is None and isinstance(obj, int) and (obj > 2 ** 64 or obj < -(2 ** 63)):
|
|
112
106
|
# Give a better error message in this case. NumPy would convert this
|
|
113
107
|
# to an object array. TODO: This won't handle large integers in lists.
|
|
114
108
|
raise OverflowError("Integer out of bounds for array dtypes")
|
|
115
|
-
|
|
116
|
-
|
|
109
|
+
|
|
110
|
+
res = np.array(obj, dtype=_np_dtype, copy=copy)
|
|
117
111
|
return Array._new(res, device=device)
|
|
118
112
|
|
|
119
113
|
|
|
120
114
|
def arange(
|
|
121
|
-
start:
|
|
115
|
+
start: float,
|
|
122
116
|
/,
|
|
123
|
-
stop:
|
|
124
|
-
step:
|
|
117
|
+
stop: float | None = None,
|
|
118
|
+
step: float = 1,
|
|
125
119
|
*,
|
|
126
|
-
dtype:
|
|
127
|
-
device:
|
|
120
|
+
dtype: DType | None = None,
|
|
121
|
+
device: Device | None = None,
|
|
128
122
|
) -> Array:
|
|
129
123
|
"""
|
|
130
124
|
Array API compatible wrapper for :py:func:`np.arange <numpy.arange>`.
|
|
@@ -136,16 +130,17 @@ def arange(
|
|
|
136
130
|
_check_valid_dtype(dtype)
|
|
137
131
|
_check_device(device)
|
|
138
132
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
return Array._new(
|
|
134
|
+
np.arange(start, stop, step, dtype=_np_dtype(dtype)),
|
|
135
|
+
device=device,
|
|
136
|
+
)
|
|
142
137
|
|
|
143
138
|
|
|
144
139
|
def empty(
|
|
145
|
-
shape:
|
|
140
|
+
shape: int | tuple[int, ...],
|
|
146
141
|
*,
|
|
147
|
-
dtype:
|
|
148
|
-
device:
|
|
142
|
+
dtype: DType | None = None,
|
|
143
|
+
device: Device | None = None,
|
|
149
144
|
) -> Array:
|
|
150
145
|
"""
|
|
151
146
|
Array API compatible wrapper for :py:func:`np.empty <numpy.empty>`.
|
|
@@ -157,13 +152,11 @@ def empty(
|
|
|
157
152
|
_check_valid_dtype(dtype)
|
|
158
153
|
_check_device(device)
|
|
159
154
|
|
|
160
|
-
|
|
161
|
-
dtype = dtype._np_dtype
|
|
162
|
-
return Array._new(np.empty(shape, dtype=dtype), device=device)
|
|
155
|
+
return Array._new(np.empty(shape, dtype=_np_dtype(dtype)), device=device)
|
|
163
156
|
|
|
164
157
|
|
|
165
158
|
def empty_like(
|
|
166
|
-
x: Array, /, *, dtype:
|
|
159
|
+
x: Array, /, *, dtype: DType | None = None, device: Device | None = None
|
|
167
160
|
) -> Array:
|
|
168
161
|
"""
|
|
169
162
|
Array API compatible wrapper for :py:func:`np.empty_like <numpy.empty_like>`.
|
|
@@ -177,19 +170,17 @@ def empty_like(
|
|
|
177
170
|
if device is None:
|
|
178
171
|
device = x.device
|
|
179
172
|
|
|
180
|
-
|
|
181
|
-
dtype = dtype._np_dtype
|
|
182
|
-
return Array._new(np.empty_like(x._array, dtype=dtype), device=device)
|
|
173
|
+
return Array._new(np.empty_like(x._array, dtype=_np_dtype(dtype)), device=device)
|
|
183
174
|
|
|
184
175
|
|
|
185
176
|
def eye(
|
|
186
177
|
n_rows: int,
|
|
187
|
-
n_cols:
|
|
178
|
+
n_cols: int | None = None,
|
|
188
179
|
/,
|
|
189
180
|
*,
|
|
190
181
|
k: int = 0,
|
|
191
|
-
dtype:
|
|
192
|
-
device:
|
|
182
|
+
dtype: DType | None = None,
|
|
183
|
+
device: Device | None = None,
|
|
193
184
|
) -> Array:
|
|
194
185
|
"""
|
|
195
186
|
Array API compatible wrapper for :py:func:`np.eye <numpy.eye>`.
|
|
@@ -201,45 +192,43 @@ def eye(
|
|
|
201
192
|
_check_valid_dtype(dtype)
|
|
202
193
|
_check_device(device)
|
|
203
194
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
195
|
+
return Array._new(
|
|
196
|
+
np.eye(n_rows, M=n_cols, k=k, dtype=_np_dtype(dtype)), device=device
|
|
197
|
+
)
|
|
208
198
|
|
|
209
|
-
_default = object()
|
|
210
199
|
|
|
211
200
|
def from_dlpack(
|
|
212
|
-
x:
|
|
201
|
+
x: SupportsDLPack,
|
|
213
202
|
/,
|
|
214
203
|
*,
|
|
215
|
-
device:
|
|
216
|
-
copy:
|
|
204
|
+
device: Device | Undef | None = _undef,
|
|
205
|
+
copy: bool | Undef | None = _undef,
|
|
217
206
|
) -> Array:
|
|
218
207
|
from ._array_object import Array
|
|
219
208
|
|
|
220
209
|
if get_array_api_strict_flags()['api_version'] < '2023.12':
|
|
221
|
-
if device is not
|
|
210
|
+
if device is not _undef:
|
|
222
211
|
raise ValueError("The device argument to from_dlpack requires at least version 2023.12 of the array API")
|
|
223
|
-
if copy is not
|
|
212
|
+
if copy is not _undef:
|
|
224
213
|
raise ValueError("The copy argument to from_dlpack requires at least version 2023.12 of the array API")
|
|
225
214
|
|
|
226
215
|
# Going to wait for upstream numpy support
|
|
227
|
-
if device is not
|
|
216
|
+
if device is not _undef:
|
|
228
217
|
_check_device(device)
|
|
229
218
|
else:
|
|
230
219
|
device = None
|
|
231
|
-
if copy not in [
|
|
220
|
+
if copy not in [_undef, None]:
|
|
232
221
|
raise NotImplementedError("The copy argument to from_dlpack is not yet implemented")
|
|
233
222
|
|
|
234
223
|
return Array._new(np.from_dlpack(x), device=device)
|
|
235
224
|
|
|
236
225
|
|
|
237
226
|
def full(
|
|
238
|
-
shape:
|
|
239
|
-
fill_value:
|
|
227
|
+
shape: int | tuple[int, ...],
|
|
228
|
+
fill_value: complex,
|
|
240
229
|
*,
|
|
241
|
-
dtype:
|
|
242
|
-
device:
|
|
230
|
+
dtype: DType | None = None,
|
|
231
|
+
device: Device | None = None,
|
|
243
232
|
) -> Array:
|
|
244
233
|
"""
|
|
245
234
|
Array API compatible wrapper for :py:func:`np.full <numpy.full>`.
|
|
@@ -253,10 +242,8 @@ def full(
|
|
|
253
242
|
|
|
254
243
|
if isinstance(fill_value, Array) and fill_value.ndim == 0:
|
|
255
244
|
fill_value = fill_value._array
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
res = np.full(shape, fill_value, dtype=dtype)
|
|
259
|
-
if _DType(res.dtype) not in _all_dtypes:
|
|
245
|
+
res = np.full(shape, fill_value, dtype=_np_dtype(dtype))
|
|
246
|
+
if DType(res.dtype) not in _all_dtypes:
|
|
260
247
|
# This will happen if the fill value is not something that NumPy
|
|
261
248
|
# coerces to one of the acceptable dtypes.
|
|
262
249
|
raise TypeError("Invalid input to full")
|
|
@@ -266,10 +253,10 @@ def full(
|
|
|
266
253
|
def full_like(
|
|
267
254
|
x: Array,
|
|
268
255
|
/,
|
|
269
|
-
fill_value:
|
|
256
|
+
fill_value: complex,
|
|
270
257
|
*,
|
|
271
|
-
dtype:
|
|
272
|
-
device:
|
|
258
|
+
dtype: DType | None = None,
|
|
259
|
+
device: Device | None = None,
|
|
273
260
|
) -> Array:
|
|
274
261
|
"""
|
|
275
262
|
Array API compatible wrapper for :py:func:`np.full_like <numpy.full_like>`.
|
|
@@ -283,10 +270,8 @@ def full_like(
|
|
|
283
270
|
if device is None:
|
|
284
271
|
device = x.device
|
|
285
272
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
res = np.full_like(x._array, fill_value, dtype=dtype)
|
|
289
|
-
if _DType(res.dtype) not in _all_dtypes:
|
|
273
|
+
res = np.full_like(x._array, fill_value, dtype=_np_dtype(dtype))
|
|
274
|
+
if DType(res.dtype) not in _all_dtypes:
|
|
290
275
|
# This will happen if the fill value is not something that NumPy
|
|
291
276
|
# coerces to one of the acceptable dtypes.
|
|
292
277
|
raise TypeError("Invalid input to full_like")
|
|
@@ -294,13 +279,13 @@ def full_like(
|
|
|
294
279
|
|
|
295
280
|
|
|
296
281
|
def linspace(
|
|
297
|
-
start:
|
|
298
|
-
stop:
|
|
282
|
+
start: complex,
|
|
283
|
+
stop: complex,
|
|
299
284
|
/,
|
|
300
285
|
num: int,
|
|
301
286
|
*,
|
|
302
|
-
dtype:
|
|
303
|
-
device:
|
|
287
|
+
dtype: DType | None = None,
|
|
288
|
+
device: Device | None = None,
|
|
304
289
|
endpoint: bool = True,
|
|
305
290
|
) -> Array:
|
|
306
291
|
"""
|
|
@@ -313,12 +298,13 @@ def linspace(
|
|
|
313
298
|
_check_valid_dtype(dtype)
|
|
314
299
|
_check_device(device)
|
|
315
300
|
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
301
|
+
return Array._new(
|
|
302
|
+
np.linspace(start, stop, num, dtype=_np_dtype(dtype), endpoint=endpoint),
|
|
303
|
+
device=device,
|
|
304
|
+
)
|
|
319
305
|
|
|
320
306
|
|
|
321
|
-
def meshgrid(*arrays: Array, indexing:
|
|
307
|
+
def meshgrid(*arrays: Array, indexing: Literal["xy", "ij"] = "xy") -> list[Array]:
|
|
322
308
|
"""
|
|
323
309
|
Array API compatible wrapper for :py:func:`np.meshgrid <numpy.meshgrid>`.
|
|
324
310
|
|
|
@@ -348,10 +334,10 @@ def meshgrid(*arrays: Array, indexing: str = "xy") -> List[Array]:
|
|
|
348
334
|
|
|
349
335
|
|
|
350
336
|
def ones(
|
|
351
|
-
shape:
|
|
337
|
+
shape: int | tuple[int, ...],
|
|
352
338
|
*,
|
|
353
|
-
dtype:
|
|
354
|
-
device:
|
|
339
|
+
dtype: DType | None = None,
|
|
340
|
+
device: Device | None = None,
|
|
355
341
|
) -> Array:
|
|
356
342
|
"""
|
|
357
343
|
Array API compatible wrapper for :py:func:`np.ones <numpy.ones>`.
|
|
@@ -363,13 +349,11 @@ def ones(
|
|
|
363
349
|
_check_valid_dtype(dtype)
|
|
364
350
|
_check_device(device)
|
|
365
351
|
|
|
366
|
-
|
|
367
|
-
dtype = dtype._np_dtype
|
|
368
|
-
return Array._new(np.ones(shape, dtype=dtype), device=device)
|
|
352
|
+
return Array._new(np.ones(shape, dtype=_np_dtype(dtype)), device=device)
|
|
369
353
|
|
|
370
354
|
|
|
371
355
|
def ones_like(
|
|
372
|
-
x: Array, /, *, dtype:
|
|
356
|
+
x: Array, /, *, dtype: DType | None = None, device: Device | None = None
|
|
373
357
|
) -> Array:
|
|
374
358
|
"""
|
|
375
359
|
Array API compatible wrapper for :py:func:`np.ones_like <numpy.ones_like>`.
|
|
@@ -383,9 +367,7 @@ def ones_like(
|
|
|
383
367
|
if device is None:
|
|
384
368
|
device = x.device
|
|
385
369
|
|
|
386
|
-
|
|
387
|
-
dtype = dtype._np_dtype
|
|
388
|
-
return Array._new(np.ones_like(x._array, dtype=dtype), device=device)
|
|
370
|
+
return Array._new(np.ones_like(x._array, dtype=_np_dtype(dtype)), device=device)
|
|
389
371
|
|
|
390
372
|
|
|
391
373
|
def tril(x: Array, /, *, k: int = 0) -> Array:
|
|
@@ -417,10 +399,10 @@ def triu(x: Array, /, *, k: int = 0) -> Array:
|
|
|
417
399
|
|
|
418
400
|
|
|
419
401
|
def zeros(
|
|
420
|
-
shape:
|
|
402
|
+
shape: int | tuple[int, ...],
|
|
421
403
|
*,
|
|
422
|
-
dtype:
|
|
423
|
-
device:
|
|
404
|
+
dtype: DType | None = None,
|
|
405
|
+
device: Device | None = None,
|
|
424
406
|
) -> Array:
|
|
425
407
|
"""
|
|
426
408
|
Array API compatible wrapper for :py:func:`np.zeros <numpy.zeros>`.
|
|
@@ -432,13 +414,11 @@ def zeros(
|
|
|
432
414
|
_check_valid_dtype(dtype)
|
|
433
415
|
_check_device(device)
|
|
434
416
|
|
|
435
|
-
|
|
436
|
-
dtype = dtype._np_dtype
|
|
437
|
-
return Array._new(np.zeros(shape, dtype=dtype), device=device)
|
|
417
|
+
return Array._new(np.zeros(shape, dtype=_np_dtype(dtype)), device=device)
|
|
438
418
|
|
|
439
419
|
|
|
440
420
|
def zeros_like(
|
|
441
|
-
x: Array, /, *, dtype:
|
|
421
|
+
x: Array, /, *, dtype: DType | None = None, device: Device | None = None
|
|
442
422
|
) -> Array:
|
|
443
423
|
"""
|
|
444
424
|
Array API compatible wrapper for :py:func:`np.zeros_like <numpy.zeros_like>`.
|
|
@@ -452,6 +432,4 @@ def zeros_like(
|
|
|
452
432
|
if device is None:
|
|
453
433
|
device = x.device
|
|
454
434
|
|
|
455
|
-
|
|
456
|
-
dtype = dtype._np_dtype
|
|
457
|
-
return Array._new(np.zeros_like(x._array, dtype=dtype), device=device)
|
|
435
|
+
return Array._new(np.zeros_like(x._array, dtype=_np_dtype(dtype)), device=device)
|
|
@@ -1,38 +1,35 @@
|
|
|
1
|
-
from
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
2
4
|
|
|
3
|
-
from ._array_object import Array
|
|
4
|
-
from ._creation_functions import _check_device
|
|
5
|
+
from ._array_object import Array, Device
|
|
6
|
+
from ._creation_functions import Undef, _check_device, _undef
|
|
5
7
|
from ._dtypes import (
|
|
6
|
-
|
|
8
|
+
DType,
|
|
7
9
|
_all_dtypes,
|
|
8
10
|
_boolean_dtypes,
|
|
9
|
-
_signed_integer_dtypes,
|
|
10
|
-
_unsigned_integer_dtypes,
|
|
11
|
-
_integer_dtypes,
|
|
12
|
-
_real_floating_dtypes,
|
|
13
11
|
_complex_floating_dtypes,
|
|
12
|
+
_integer_dtypes,
|
|
14
13
|
_numeric_dtypes,
|
|
14
|
+
_real_floating_dtypes,
|
|
15
15
|
_result_type,
|
|
16
|
+
_signed_integer_dtypes,
|
|
17
|
+
_unsigned_integer_dtypes,
|
|
16
18
|
)
|
|
17
19
|
from ._flags import get_array_api_strict_flags
|
|
18
20
|
|
|
19
|
-
from dataclasses import dataclass
|
|
20
|
-
from typing import TYPE_CHECKING
|
|
21
|
-
|
|
22
|
-
if TYPE_CHECKING:
|
|
23
|
-
from typing import List, Tuple, Union, Optional
|
|
24
|
-
from ._typing import Dtype, Device
|
|
25
|
-
|
|
26
|
-
import numpy as np
|
|
27
|
-
|
|
28
|
-
# Use to emulate the asarray(device) argument not existing in 2022.12
|
|
29
|
-
_default = object()
|
|
30
21
|
|
|
31
22
|
# Note: astype is a function, not an array method as in NumPy.
|
|
32
23
|
def astype(
|
|
33
|
-
x: Array,
|
|
24
|
+
x: Array,
|
|
25
|
+
dtype: DType,
|
|
26
|
+
/,
|
|
27
|
+
*,
|
|
28
|
+
copy: bool = True,
|
|
29
|
+
# _default is used to emulate the device argument not existing in 2022.12
|
|
30
|
+
device: Device | Undef | None = _undef,
|
|
34
31
|
) -> Array:
|
|
35
|
-
if device is not
|
|
32
|
+
if device is not _undef:
|
|
36
33
|
if get_array_api_strict_flags()['api_version'] >= '2023.12':
|
|
37
34
|
_check_device(device)
|
|
38
35
|
else:
|
|
@@ -52,7 +49,7 @@ def astype(
|
|
|
52
49
|
return Array._new(x._array.astype(dtype=dtype._np_dtype, copy=copy), device=device)
|
|
53
50
|
|
|
54
51
|
|
|
55
|
-
def broadcast_arrays(*arrays: Array) ->
|
|
52
|
+
def broadcast_arrays(*arrays: Array) -> list[Array]:
|
|
56
53
|
"""
|
|
57
54
|
Array API compatible wrapper for :py:func:`np.broadcast_arrays <numpy.broadcast_arrays>`.
|
|
58
55
|
|
|
@@ -65,7 +62,7 @@ def broadcast_arrays(*arrays: Array) -> List[Array]:
|
|
|
65
62
|
]
|
|
66
63
|
|
|
67
64
|
|
|
68
|
-
def broadcast_to(x: Array, /, shape:
|
|
65
|
+
def broadcast_to(x: Array, /, shape: tuple[int, ...]) -> Array:
|
|
69
66
|
"""
|
|
70
67
|
Array API compatible wrapper for :py:func:`np.broadcast_to <numpy.broadcast_to>`.
|
|
71
68
|
|
|
@@ -76,7 +73,7 @@ def broadcast_to(x: Array, /, shape: Tuple[int, ...]) -> Array:
|
|
|
76
73
|
return Array._new(np.broadcast_to(x._array, shape), device=x.device)
|
|
77
74
|
|
|
78
75
|
|
|
79
|
-
def can_cast(from_:
|
|
76
|
+
def can_cast(from_: DType | Array, to: DType, /) -> bool:
|
|
80
77
|
"""
|
|
81
78
|
Array API compatible wrapper for :py:func:`np.can_cast <numpy.can_cast>`.
|
|
82
79
|
|
|
@@ -103,7 +100,9 @@ def can_cast(from_: Union[Dtype, Array], to: Dtype, /) -> bool:
|
|
|
103
100
|
|
|
104
101
|
# These are internal objects for the return types of finfo and iinfo, since
|
|
105
102
|
# the NumPy versions contain extra data that isn't part of the spec.
|
|
106
|
-
|
|
103
|
+
# There should be no expectation for them to be comparable, hashable, or writeable.
|
|
104
|
+
|
|
105
|
+
@dataclass(frozen=True, eq=False)
|
|
107
106
|
class finfo_object:
|
|
108
107
|
bits: int
|
|
109
108
|
# Note: The types of the float data here are float, whereas in NumPy they
|
|
@@ -112,26 +111,35 @@ class finfo_object:
|
|
|
112
111
|
max: float
|
|
113
112
|
min: float
|
|
114
113
|
smallest_normal: float
|
|
115
|
-
dtype:
|
|
114
|
+
dtype: DType
|
|
115
|
+
|
|
116
|
+
__hash__ = NotImplemented
|
|
116
117
|
|
|
117
118
|
|
|
118
|
-
@dataclass
|
|
119
|
+
@dataclass(frozen=True, eq=False)
|
|
119
120
|
class iinfo_object:
|
|
120
121
|
bits: int
|
|
121
122
|
max: int
|
|
122
123
|
min: int
|
|
123
|
-
dtype:
|
|
124
|
+
dtype: DType
|
|
124
125
|
|
|
126
|
+
__hash__ = NotImplemented
|
|
125
127
|
|
|
126
|
-
|
|
128
|
+
|
|
129
|
+
def finfo(type: DType | Array, /) -> finfo_object:
|
|
127
130
|
"""
|
|
128
131
|
Array API compatible wrapper for :py:func:`np.finfo <numpy.finfo>`.
|
|
129
132
|
|
|
130
133
|
See its docstring for more information.
|
|
131
134
|
"""
|
|
132
|
-
if isinstance(type,
|
|
133
|
-
|
|
134
|
-
|
|
135
|
+
if isinstance(type, Array):
|
|
136
|
+
np_type = type._dtype._np_dtype
|
|
137
|
+
elif isinstance(type, DType):
|
|
138
|
+
np_type = type._np_dtype
|
|
139
|
+
else:
|
|
140
|
+
raise TypeError(f"'type' must be a dtype or array, not {type!r}")
|
|
141
|
+
|
|
142
|
+
fi = np.finfo(np_type)
|
|
135
143
|
# Note: The types of the float data here are float, whereas in NumPy they
|
|
136
144
|
# are scalars of the corresponding float dtype.
|
|
137
145
|
return finfo_object(
|
|
@@ -140,35 +148,39 @@ def finfo(type: Union[Dtype, Array], /) -> finfo_object:
|
|
|
140
148
|
float(fi.max),
|
|
141
149
|
float(fi.min),
|
|
142
150
|
float(fi.smallest_normal),
|
|
143
|
-
fi.dtype,
|
|
151
|
+
DType(fi.dtype),
|
|
144
152
|
)
|
|
145
153
|
|
|
146
154
|
|
|
147
|
-
def iinfo(type:
|
|
155
|
+
def iinfo(type: DType | Array, /) -> iinfo_object:
|
|
148
156
|
"""
|
|
149
157
|
Array API compatible wrapper for :py:func:`np.iinfo <numpy.iinfo>`.
|
|
150
158
|
|
|
151
159
|
See its docstring for more information.
|
|
152
160
|
"""
|
|
153
|
-
if isinstance(type,
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
161
|
+
if isinstance(type, Array):
|
|
162
|
+
np_type = type._dtype._np_dtype
|
|
163
|
+
elif isinstance(type, DType):
|
|
164
|
+
np_type = type._np_dtype
|
|
165
|
+
else:
|
|
166
|
+
raise TypeError(f"'type' must be a dtype or array, not {type!r}")
|
|
167
|
+
|
|
168
|
+
ii = np.iinfo(np_type)
|
|
169
|
+
return iinfo_object(ii.bits, ii.max, ii.min, DType(ii.dtype))
|
|
157
170
|
|
|
158
171
|
|
|
159
172
|
# Note: isdtype is a new function from the 2022.12 array API specification.
|
|
160
|
-
def isdtype(
|
|
161
|
-
dtype: Dtype, kind: Union[Dtype, str, Tuple[Union[Dtype, str], ...]]
|
|
162
|
-
) -> bool:
|
|
173
|
+
def isdtype(dtype: DType, kind: DType | str | tuple[DType | str, ...]) -> bool:
|
|
163
174
|
"""
|
|
164
|
-
Returns a boolean indicating whether a provided dtype is of a specified
|
|
175
|
+
Returns a boolean indicating whether a provided dtype is of a specified
|
|
176
|
+
data type ``kind``.
|
|
165
177
|
|
|
166
178
|
See
|
|
167
179
|
https://data-apis.org/array-api/latest/API_specification/generated/array_api.isdtype.html
|
|
168
180
|
for more details
|
|
169
181
|
"""
|
|
170
|
-
if not isinstance(dtype,
|
|
171
|
-
|
|
182
|
+
if not isinstance(dtype, DType):
|
|
183
|
+
raise TypeError(f"'dtype' must be a dtype, not a {type(dtype)!r}")
|
|
172
184
|
|
|
173
185
|
if isinstance(kind, tuple):
|
|
174
186
|
# Disallow nested tuples
|
|
@@ -197,7 +209,8 @@ def isdtype(
|
|
|
197
209
|
else:
|
|
198
210
|
raise TypeError(f"'kind' must be a dtype, str, or tuple of dtypes and strs, not {type(kind).__name__}")
|
|
199
211
|
|
|
200
|
-
|
|
212
|
+
|
|
213
|
+
def result_type(*arrays_and_dtypes: Array | DType | complex) -> DType:
|
|
201
214
|
"""
|
|
202
215
|
Array API compatible wrapper for :py:func:`np.result_type <numpy.result_type>`.
|
|
203
216
|
|
|
@@ -207,35 +220,31 @@ def result_type(*arrays_and_dtypes: Union[Array, Dtype, int, float, complex, boo
|
|
|
207
220
|
# required by the spec rather than using np.result_type. NumPy implements
|
|
208
221
|
# too many extra type promotions like int64 + uint64 -> float64, and does
|
|
209
222
|
# value-based casting on scalar arrays.
|
|
210
|
-
|
|
223
|
+
dtypes = []
|
|
211
224
|
scalars = []
|
|
212
225
|
for a in arrays_and_dtypes:
|
|
213
|
-
if isinstance(a,
|
|
214
|
-
a
|
|
226
|
+
if isinstance(a, DType):
|
|
227
|
+
dtypes.append(a)
|
|
228
|
+
elif isinstance(a, Array):
|
|
229
|
+
dtypes.append(a.dtype)
|
|
215
230
|
elif isinstance(a, (bool, int, float, complex)):
|
|
216
231
|
scalars.append(a)
|
|
217
|
-
|
|
218
|
-
raise TypeError(
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
# remove python scalars
|
|
222
|
-
A = [a for a in A if not isinstance(a, (bool, int, float, complex))]
|
|
232
|
+
else:
|
|
233
|
+
raise TypeError(
|
|
234
|
+
"result_type() inputs must be Array API arrays, dtypes, or scalars"
|
|
235
|
+
)
|
|
223
236
|
|
|
224
|
-
if
|
|
237
|
+
if not dtypes:
|
|
225
238
|
raise ValueError("at least one array or dtype is required")
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
t = A[0]
|
|
230
|
-
for t2 in A[1:]:
|
|
231
|
-
t = _result_type(t, t2)
|
|
232
|
-
result = t
|
|
239
|
+
result = dtypes[0]
|
|
240
|
+
for t2 in dtypes[1:]:
|
|
241
|
+
result = _result_type(result, t2)
|
|
233
242
|
|
|
234
|
-
if
|
|
243
|
+
if not scalars:
|
|
235
244
|
return result
|
|
236
245
|
|
|
237
246
|
if get_array_api_strict_flags()['api_version'] <= '2023.12':
|
|
238
|
-
raise TypeError("result_type() inputs must be
|
|
247
|
+
raise TypeError("result_type() inputs must be Array API arrays or dtypes")
|
|
239
248
|
|
|
240
249
|
# promote python scalars given the result_type for all arrays/dtypes
|
|
241
250
|
from ._creation_functions import empty
|