array-api-strict 2.5__py3-none-any.whl → 2.6__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.
@@ -20,7 +20,7 @@ import sys
20
20
  from collections.abc import Iterator
21
21
  from enum import IntEnum
22
22
  from types import EllipsisType, ModuleType
23
- from typing import Any, Final, Literal, SupportsIndex, Callable
23
+ from typing import Any, Literal, SupportsIndex, Callable
24
24
 
25
25
  import numpy as np
26
26
  import numpy.typing as npt
@@ -40,35 +40,14 @@ from ._dtypes import (
40
40
  _real_to_complex_map,
41
41
  _result_type,
42
42
  )
43
+ from ._devices import (
44
+ CPU_DEVICE, Device, device_supports_dtype, _normalize_dl_device, _DLPACK_DEVICE_FOR,
45
+ DLDeviceType
46
+ )
43
47
  from ._flags import get_array_api_strict_flags, set_array_api_strict_flags
44
48
  from ._typing import PyCapsule
45
49
 
46
50
 
47
- class Device:
48
- _device: Final[str]
49
- __slots__ = ("_device", "__weakref__")
50
-
51
- def __init__(self, device: str = "CPU_DEVICE"):
52
- if device not in ("CPU_DEVICE", "device1", "device2"):
53
- raise ValueError(f"The device '{device}' is not a valid choice.")
54
- self._device = device
55
-
56
- def __repr__(self) -> str:
57
- return f"array_api_strict.Device('{self._device}')"
58
-
59
- def __eq__(self, other: object) -> bool:
60
- if not isinstance(other, Device):
61
- return False
62
- return self._device == other._device
63
-
64
- def __hash__(self) -> int:
65
- return hash(("Device", self._device))
66
-
67
-
68
- CPU_DEVICE = Device()
69
- ALL_DEVICES = (CPU_DEVICE, Device("device1"), Device("device2"))
70
-
71
-
72
51
  class Array:
73
52
  """
74
53
  n-d array object for the array API namespace.
@@ -113,10 +92,15 @@ class Array:
113
92
  raise TypeError(
114
93
  f"The array_api_strict namespace does not support the dtype '{x.dtype}'"
115
94
  )
116
- obj._array = x
117
- obj._dtype = _dtype
95
+
118
96
  if device is None:
119
97
  device = CPU_DEVICE
98
+ if not device_supports_dtype(device, _dtype):
99
+ raise ValueError(f"Device {device!r} does not support dtype={_dtype!r}.")
100
+
101
+ obj._array = x
102
+ obj._dtype = _dtype
103
+
120
104
  obj._device = device
121
105
  return obj
122
106
 
@@ -400,7 +384,7 @@ class Array:
400
384
  isinstance(i, SupportsIndex) # i.e. ints
401
385
  or isinstance(i, slice)
402
386
  or i == Ellipsis
403
- or i is None
387
+ or (op == "getitem" and i is None) # `None` disallowed in setitem
404
388
  or isinstance(i, Array)
405
389
  or isinstance(i, np.ndarray)
406
390
  ):
@@ -630,22 +614,40 @@ class Array:
630
614
  raise NotImplementedError("The copy argument to __dlpack__ is not yet implemented")
631
615
 
632
616
  return self._array.__dlpack__(stream=stream)
633
- else:
634
- kwargs = {'stream': stream}
635
- if max_version is not _undef:
636
- kwargs['max_version'] = max_version
637
- if dl_device is not _undef:
638
- kwargs['dl_device'] = dl_device
639
- if copy is not _undef:
640
- kwargs['copy'] = copy
641
- return self._array.__dlpack__(**kwargs)
617
+
618
+ kwargs: dict[str, Any] = {'stream': stream}
619
+ self_dl_device = _normalize_dl_device(*_DLPACK_DEVICE_FOR[self._device])
620
+ cpu_dl_device = _normalize_dl_device(DLDeviceType.kDLCPU, 0)
621
+ numpy_dl_device: tuple[IntEnum, int] | None = None
622
+
623
+ if dl_device not in [_undef, None]:
624
+ requested = _normalize_dl_device(dl_device[0], dl_device[1])
625
+ if requested == self_dl_device:
626
+ pass
627
+ elif requested == cpu_dl_device and self_dl_device != cpu_dl_device:
628
+ if copy is False:
629
+ raise BufferError(
630
+ "Cannot export array to CPU without copying when copy=False"
631
+ )
632
+ if copy is _undef:
633
+ copy = True
634
+ numpy_dl_device = (DLDeviceType.kDLCPU, 0)
635
+ else:
636
+ raise BufferError("unsupported device requested")
637
+
638
+ if max_version is not _undef:
639
+ kwargs['max_version'] = max_version
640
+ if numpy_dl_device is not None:
641
+ kwargs['dl_device'] = numpy_dl_device
642
+ if copy is not _undef:
643
+ kwargs['copy'] = copy
644
+ return self._array.__dlpack__(**kwargs)
642
645
 
643
646
  def __dlpack_device__(self) -> tuple[IntEnum, int]:
644
647
  """
645
648
  Performs the operation __dlpack_device__.
646
649
  """
647
- # Note: device support is required for this
648
- return self._array.__dlpack_device__()
650
+ return _DLPACK_DEVICE_FOR[self._device]
649
651
 
650
652
  def __eq__(self, other: Array | complex, /) -> Array: # type: ignore[override]
651
653
  """
@@ -960,6 +962,10 @@ class Array:
960
962
  other = value
961
963
  if isinstance(value, (bool, int, float, complex)):
962
964
  other = self._promote_scalar(value)
965
+ else:
966
+ if value.device != self.device:
967
+ raise ValueError(f"mismatched devices: {self.device = } != {value.device =}.")
968
+
963
969
  dt = _result_type(self.dtype, other.dtype)
964
970
  if dt != self.dtype:
965
971
  raise TypeError(f"mismatched dtypes: {self.dtype = } and {other.dtype = }")
@@ -5,7 +5,11 @@ from typing import TYPE_CHECKING, Literal
5
5
 
6
6
  import numpy as np
7
7
 
8
- from ._dtypes import DType, _all_dtypes, _np_dtype
8
+ from ._dtypes import DType, _all_dtypes, _np_dtype, bool as xp_bool
9
+ from ._devices import (
10
+ Device, device_supports_dtype, get_default_dtypes,
11
+ check_device as _check_device
12
+ )
9
13
  from ._flags import get_array_api_strict_flags
10
14
  from ._typing import NestedSequence, SupportsBufferProtocol, SupportsDLPack
11
15
 
@@ -14,7 +18,7 @@ if TYPE_CHECKING:
14
18
  from typing_extensions import TypeIs
15
19
 
16
20
  # Circular import
17
- from ._array_object import Array, Device
21
+ from ._array_object import Array
18
22
 
19
23
 
20
24
  class Undef(Enum):
@@ -24,10 +28,15 @@ class Undef(Enum):
24
28
  _undef = Undef.UNDEF
25
29
 
26
30
 
27
- def _check_valid_dtype(dtype: DType | None) -> None:
31
+ def _check_valid_dtype(dtype: DType | None, device: Device | None = None) -> None:
28
32
  # Note: Only spelling dtypes as the dtype objects is supported.
29
- if dtype not in (None,) + _all_dtypes:
30
- raise ValueError(f"dtype must be one of the supported dtypes, got {dtype!r}")
33
+ if dtype is not None:
34
+ if dtype not in _all_dtypes:
35
+ raise ValueError(f"dtype must be one of the supported dtypes, got {dtype!r}")
36
+
37
+ if device is not None:
38
+ if not device_supports_dtype(device, dtype):
39
+ raise ValueError(f"Device {device!r} does not support dtype={dtype!r}.")
31
40
 
32
41
 
33
42
  def _supports_buffer_protocol(obj: object) -> TypeIs[SupportsBufferProtocol]:
@@ -38,18 +47,6 @@ def _supports_buffer_protocol(obj: object) -> TypeIs[SupportsBufferProtocol]:
38
47
  return True
39
48
 
40
49
 
41
- def _check_device(device: Device | None) -> None:
42
- # _array_object imports in this file are inside the functions to avoid
43
- # circular imports
44
- from ._array_object import ALL_DEVICES, Device
45
-
46
- if device is not None and not isinstance(device, Device):
47
- raise ValueError(f"Unsupported device {device!r}")
48
-
49
- if device is not None and device not in ALL_DEVICES:
50
- raise ValueError(f"Unsupported device {device!r}")
51
-
52
-
53
50
  def asarray(
54
51
  obj: Array | complex | NestedSequence[complex] | SupportsBufferProtocol,
55
52
  /,
@@ -65,11 +62,12 @@ def asarray(
65
62
  """
66
63
  from ._array_object import Array
67
64
 
68
- _check_valid_dtype(dtype)
65
+ _check_device(device)
66
+ _check_valid_dtype(dtype, device)
69
67
  _np_dtype = None
70
68
  if dtype is not None:
71
69
  _np_dtype = dtype._np_dtype
72
- _check_device(device)
70
+
73
71
  if isinstance(obj, Array) and device is None:
74
72
  device = obj.device
75
73
 
@@ -108,6 +106,27 @@ def asarray(
108
106
  raise OverflowError("Integer out of bounds for array dtypes")
109
107
 
110
108
  res = np.array(obj, dtype=_np_dtype, copy=copy)
109
+
110
+ # numpy default dtype may differ; if so, adjust the dtype
111
+ if dtype is None and device is not None:
112
+ res_dtype = DType(res.dtype)
113
+ # The dtype selected by Numpy might not be the default dtype
114
+ # on this device. We thus find the default dtype for the dtype "kind", and
115
+ # cast to the device-appropriate default.
116
+ from ._data_type_functions import isdtype
117
+ if isdtype(res_dtype, "bool"):
118
+ target_dtype = DType("bool")
119
+ elif isdtype(res_dtype, "integral"):
120
+ target_dtype = get_default_dtypes(device)["integral"]
121
+ elif isdtype(res_dtype, "real floating"):
122
+ target_dtype = get_default_dtypes(device)["real floating"]
123
+ elif isdtype(res_dtype, "complex floating"):
124
+ target_dtype = get_default_dtypes(device)["complex floating"]
125
+ else:
126
+ raise ValueError(f"{res_dtype = } not understood.")
127
+
128
+ res = res.astype(target_dtype._np_dtype)
129
+
111
130
  return Array._new(res, device=device)
112
131
 
113
132
 
@@ -127,8 +146,13 @@ def arange(
127
146
  """
128
147
  from ._array_object import Array
129
148
 
130
- _check_valid_dtype(dtype)
131
149
  _check_device(device)
150
+ _check_valid_dtype(dtype, device)
151
+ if dtype is None:
152
+ if any(isinstance(x, float) for x in (start, stop, step)):
153
+ dtype = get_default_dtypes(device)["real floating"]
154
+ else:
155
+ dtype = get_default_dtypes(device)["integral"]
132
156
 
133
157
  return Array._new(
134
158
  np.arange(start, stop, step, dtype=_np_dtype(dtype)),
@@ -149,8 +173,10 @@ def empty(
149
173
  """
150
174
  from ._array_object import Array
151
175
 
152
- _check_valid_dtype(dtype)
153
176
  _check_device(device)
177
+ _check_valid_dtype(dtype, device)
178
+ if dtype is None:
179
+ dtype = get_default_dtypes(device)["real floating"]
154
180
 
155
181
  return Array._new(np.empty(shape, dtype=_np_dtype(dtype)), device=device)
156
182
 
@@ -165,10 +191,12 @@ def empty_like(
165
191
  """
166
192
  from ._array_object import Array
167
193
 
168
- _check_valid_dtype(dtype)
169
194
  _check_device(device)
170
195
  if device is None:
171
196
  device = x.device
197
+ if dtype is None:
198
+ dtype = x.dtype
199
+ _check_valid_dtype(dtype, device)
172
200
 
173
201
  return Array._new(np.empty_like(x._array, dtype=_np_dtype(dtype)), device=device)
174
202
 
@@ -189,8 +217,10 @@ def eye(
189
217
  """
190
218
  from ._array_object import Array
191
219
 
192
- _check_valid_dtype(dtype)
193
220
  _check_device(device)
221
+ _check_valid_dtype(dtype, device)
222
+ if dtype is None:
223
+ dtype = get_default_dtypes(device)["real floating"]
194
224
 
195
225
  return Array._new(
196
226
  np.eye(n_rows, M=n_cols, k=k, dtype=_np_dtype(dtype)), device=device
@@ -212,15 +242,20 @@ def from_dlpack(
212
242
  if copy is not _undef:
213
243
  raise ValueError("The copy argument to from_dlpack requires at least version 2023.12 of the array API")
214
244
 
215
- # Going to wait for upstream numpy support
216
245
  if device is not _undef:
217
246
  _check_device(device)
218
247
  else:
219
248
  device = None
220
- if copy not in [_undef, None]:
221
- raise NotImplementedError("The copy argument to from_dlpack is not yet implemented")
249
+ if hasattr(x, "__dlpack_device__"):
250
+ from ._devices import _device_from_dlpack_device
222
251
 
223
- return Array._new(np.from_dlpack(x), device=device)
252
+ dl_type, dl_id = x.__dlpack_device__()
253
+ device = _device_from_dlpack_device(dl_type, dl_id)
254
+ if copy in [_undef, None]:
255
+ # numpy 1.26 does not have the copy= arg
256
+ return Array._new(np.from_dlpack(x), device=device)
257
+
258
+ return Array._new(np.from_dlpack(x, copy=copy), device=device)
224
259
 
225
260
 
226
261
  def full(
@@ -237,12 +272,22 @@ def full(
237
272
  """
238
273
  from ._array_object import Array
239
274
 
240
- _check_valid_dtype(dtype)
241
275
  _check_device(device)
276
+ _check_valid_dtype(dtype, device)
242
277
 
243
278
  if not isinstance(fill_value, bool | int | float | complex):
244
279
  msg = f"Expected Python scalar fill_value, got type {type(fill_value)}"
245
280
  raise TypeError(msg)
281
+
282
+ if dtype is None:
283
+ if type(fill_value) == bool:
284
+ dtype = xp_bool
285
+ else:
286
+ kind = {
287
+ int: "integral", float: "real floating", complex: "complex floating"
288
+ }[type(fill_value)]
289
+ dtype = get_default_dtypes(device)[kind]
290
+
246
291
  res = np.full(shape, fill_value, dtype=_np_dtype(dtype))
247
292
  if DType(res.dtype) not in _all_dtypes:
248
293
  # This will happen if the fill value is not something that NumPy
@@ -266,10 +311,12 @@ def full_like(
266
311
  """
267
312
  from ._array_object import Array
268
313
 
269
- _check_valid_dtype(dtype)
270
314
  _check_device(device)
271
315
  if device is None:
272
316
  device = x.device
317
+ if dtype is None:
318
+ dtype = x.dtype
319
+ _check_valid_dtype(dtype, device)
273
320
 
274
321
  if not isinstance(fill_value, bool | int | float | complex):
275
322
  msg = f"Expected Python scalar fill_value, got type {type(fill_value)}"
@@ -300,8 +347,13 @@ def linspace(
300
347
  """
301
348
  from ._array_object import Array
302
349
 
303
- _check_valid_dtype(dtype)
304
350
  _check_device(device)
351
+ _check_valid_dtype(dtype, device)
352
+ if dtype is None:
353
+ if isinstance(start, complex) or isinstance(stop, complex):
354
+ dtype = get_default_dtypes(device)["complex floating"]
355
+ else:
356
+ dtype = get_default_dtypes(device)["real floating"]
305
357
 
306
358
  return Array._new(
307
359
  np.linspace(start, stop, num, dtype=_np_dtype(dtype), endpoint=endpoint),
@@ -353,8 +405,10 @@ def ones(
353
405
  """
354
406
  from ._array_object import Array
355
407
 
356
- _check_valid_dtype(dtype)
357
408
  _check_device(device)
409
+ _check_valid_dtype(dtype, device)
410
+ if dtype is None:
411
+ dtype = get_default_dtypes(device)["real floating"]
358
412
 
359
413
  return Array._new(np.ones(shape, dtype=_np_dtype(dtype)), device=device)
360
414
 
@@ -369,10 +423,12 @@ def ones_like(
369
423
  """
370
424
  from ._array_object import Array
371
425
 
372
- _check_valid_dtype(dtype)
373
426
  _check_device(device)
374
427
  if device is None:
375
428
  device = x.device
429
+ if dtype is None:
430
+ dtype = x.dtype
431
+ _check_valid_dtype(dtype, device)
376
432
 
377
433
  return Array._new(np.ones_like(x._array, dtype=_np_dtype(dtype)), device=device)
378
434
 
@@ -418,8 +474,10 @@ def zeros(
418
474
  """
419
475
  from ._array_object import Array
420
476
 
421
- _check_valid_dtype(dtype)
422
477
  _check_device(device)
478
+ _check_valid_dtype(dtype, device)
479
+ if dtype is None:
480
+ dtype = get_default_dtypes(device)["real floating"]
423
481
 
424
482
  return Array._new(np.zeros(shape, dtype=_np_dtype(dtype)), device=device)
425
483
 
@@ -434,9 +492,11 @@ def zeros_like(
434
492
  """
435
493
  from ._array_object import Array
436
494
 
437
- _check_valid_dtype(dtype)
438
495
  _check_device(device)
439
496
  if device is None:
440
497
  device = x.device
498
+ if dtype is None:
499
+ dtype = x.dtype
500
+ _check_valid_dtype(dtype, device)
441
501
 
442
502
  return Array._new(np.zeros_like(x._array, dtype=_np_dtype(dtype)), device=device)
@@ -0,0 +1,136 @@
1
+ from typing import Final
2
+ from enum import IntEnum
3
+
4
+ from ._dtypes import (
5
+ DType, float32, float64, complex64, complex128, int64,
6
+ _all_dtypes, _boolean_dtypes, _signed_integer_dtypes,
7
+ _unsigned_integer_dtypes, _integer_dtypes, _real_floating_dtypes,
8
+ _complex_floating_dtypes, _numeric_dtypes
9
+ )
10
+
11
+ _ALL_DEVICE_NAMES = ("CPU_DEVICE", "device1", "device2", "no_float64")
12
+
13
+ class Device:
14
+ _device: Final[str]
15
+ __slots__ = ("_device", "__weakref__")
16
+
17
+ def __init__(self, device: str = "CPU_DEVICE"):
18
+ if device not in _ALL_DEVICE_NAMES:
19
+ raise ValueError(f"The device '{device}' is not a valid choice.")
20
+ self._device = device
21
+
22
+ def __repr__(self) -> str:
23
+ return f"array_api_strict.Device('{self._device}')"
24
+
25
+ def __eq__(self, other: object) -> bool:
26
+ if not isinstance(other, Device):
27
+ return False
28
+ return self._device == other._device
29
+
30
+ def __hash__(self) -> int:
31
+ return hash(("Device", self._device))
32
+
33
+
34
+ CPU_DEVICE = Device()
35
+ NO_FLOAT64_DEVICE = Device("no_float64")
36
+
37
+ ALL_DEVICES = (CPU_DEVICE, Device("device1"), Device("device2"), NO_FLOAT64_DEVICE)
38
+
39
+ class DLDeviceType(IntEnum):
40
+ kDLCPU = 1
41
+ kDLCUDA = 2
42
+ kDLMETAL = 8
43
+
44
+
45
+ _DLPACK_DEVICE_FOR: Final[dict[Device, tuple[DLDeviceType, int]]] = {
46
+ CPU_DEVICE: (DLDeviceType.kDLCPU, 0),
47
+ Device("device1"): (DLDeviceType.kDLCUDA, 0),
48
+ Device("device2"): (DLDeviceType.kDLCUDA, 1),
49
+ NO_FLOAT64_DEVICE: (DLDeviceType.kDLMETAL, 0),
50
+ }
51
+
52
+ _DLPACK_DEVICE_TO_LOGICAL: Final[dict[tuple[int, int], Device]] = {
53
+ (int(device_type), device_id): logical_device
54
+ for logical_device, (device_type, device_id) in _DLPACK_DEVICE_FOR.items()
55
+ }
56
+
57
+
58
+ def _normalize_dl_device(device_type: IntEnum | int, device_id: int) -> tuple[int, int]:
59
+ return (int(device_type), device_id)
60
+
61
+
62
+ def _device_from_dlpack_device(
63
+ device_type: IntEnum | int, device_id: int
64
+ ) -> Device:
65
+ # NB: if the (device_type, device_id) pair not known, raise
66
+ return _DLPACK_DEVICE_TO_LOGICAL[_normalize_dl_device(device_type, device_id)]
67
+
68
+
69
+ def check_device(device: Device | None) -> None:
70
+ if device is not None and not isinstance(device, Device):
71
+ raise ValueError(f"Unsupported device {device!r}")
72
+
73
+ if device is not None and device not in ALL_DEVICES:
74
+ raise ValueError(f"Unsupported device {device!r}")
75
+
76
+
77
+ # Helpers for device-specific dtype support
78
+
79
+ def get_default_dtypes(device: Device | None = None) -> dict[str, DType]:
80
+ if device == NO_FLOAT64_DEVICE:
81
+ # mimic an MPS device which does not have float64 at all
82
+ return {
83
+ "real floating": float32,
84
+ "complex floating": complex64,
85
+ "integral": int64,
86
+ "indexing": int64,
87
+ }
88
+ elif device == Device('device2'):
89
+ # mimic a torch CPU device: support float64 but default to float32
90
+ return {
91
+ "real floating": float32,
92
+ "complex floating": complex64,
93
+ "integral": int64,
94
+ "indexing": int64,
95
+ }
96
+ else:
97
+ return {
98
+ "real floating": float64,
99
+ "complex floating": complex128,
100
+ "integral": int64,
101
+ "indexing": int64,
102
+ }
103
+
104
+
105
+ def device_supports_dtype(device: Device | None, dtype: DType |None) -> bool:
106
+ """True if `device` supports `dtype`, False otherwise."""
107
+ # Device("no_float64") supports all dtypes except float64 and complex128
108
+ if device == NO_FLOAT64_DEVICE:
109
+ return dtype not in (float64, complex128)
110
+
111
+ # All other devices support all dtypes
112
+ return True
113
+
114
+
115
+ def _map_supported(dtypes: list[DType], device: Device) -> dict[str, DType]:
116
+ return {
117
+ dt._canonical_name: dt
118
+ for dt in dtypes
119
+ if device_supports_dtype(device, dt)
120
+ }
121
+
122
+
123
+ # _info.dtypes() maps "kind" -> dict of {name: dtype}
124
+ # Note that "kinds" differ from "categories" above, per the spec.
125
+
126
+ _kind_to_dtypes = {
127
+ None: _all_dtypes,
128
+ "bool": _boolean_dtypes,
129
+ "signed integer": _signed_integer_dtypes,
130
+ "unsigned integer": _unsigned_integer_dtypes,
131
+ "integral": _integer_dtypes,
132
+ "real floating": _real_floating_dtypes,
133
+ "complex floating": _complex_floating_dtypes,
134
+ "numeric": _numeric_dtypes
135
+ }
136
+
@@ -11,9 +11,11 @@ import numpy.typing as npt
11
11
 
12
12
  class DType:
13
13
  _np_dtype: Final[np.dtype[Any]]
14
- __slots__ = ("_np_dtype", "__weakref__")
14
+ _canonical_name: Final[Any]
15
+ __slots__ = ("_np_dtype", "_canonical_name", "__weakref__")
15
16
 
16
17
  def __init__(self, np_dtype: npt.DTypeLike):
18
+ self._canonical_name = np_dtype
17
19
  self._np_dtype = np.dtype(np_dtype)
18
20
 
19
21
  def __repr__(self) -> str:
array_api_strict/_fft.py CHANGED
@@ -3,7 +3,8 @@ from typing import Literal
3
3
 
4
4
  import numpy as np
5
5
 
6
- from ._array_object import ALL_DEVICES, Array, Device
6
+ from ._array_object import Array
7
+ from ._devices import ALL_DEVICES, Device, device_supports_dtype
7
8
  from ._data_type_functions import astype
8
9
  from ._dtypes import (
9
10
  DType,
@@ -13,6 +14,7 @@ from ._dtypes import (
13
14
  complex64,
14
15
  float32,
15
16
  )
17
+ from ._info import __array_namespace_info__
16
18
  from ._flags import requires_extension
17
19
 
18
20
 
@@ -268,6 +270,15 @@ def fftfreq(
268
270
  np_result = np.fft.fftfreq(n, d=d)
269
271
  if dtype:
270
272
  np_result = np_result.astype(dtype._np_dtype)
273
+
274
+ if not device_supports_dtype(device, DType(np_result.dtype)):
275
+ if dtype:
276
+ # user input unsupported
277
+ raise ValueError(f"Device {device!r} does not support dtype={dtype!r}.")
278
+
279
+ dt = __array_namespace_info__().default_dtypes(device=device)["real floating"]
280
+ np_result = np_result.astype(dt._np_dtype)
281
+
271
282
  return Array._new(np_result, device=device)
272
283
 
273
284
  @requires_extension('fft')
@@ -292,6 +303,15 @@ def rfftfreq(
292
303
  np_result = np.fft.rfftfreq(n, d=d)
293
304
  if dtype:
294
305
  np_result = np_result.astype(dtype._np_dtype)
306
+
307
+ if not device_supports_dtype(device, DType(np_result.dtype)):
308
+ if dtype:
309
+ # user input unsupported
310
+ raise ValueError(f"Device {device!r} does not support dtype={dtype!r}.")
311
+
312
+ dt = __array_namespace_info__().default_dtypes(device=device)["real floating"]
313
+ np_result = np_result.astype(dt._np_dtype)
314
+
295
315
  return Array._new(np_result, device=device)
296
316
 
297
317
  @requires_extension('fft')
array_api_strict/_info.py CHANGED
@@ -1,7 +1,7 @@
1
1
  import numpy as np
2
2
 
3
- from . import _dtypes as dt
4
- from ._array_object import ALL_DEVICES, CPU_DEVICE, Device
3
+ from . import _devices
4
+ from ._devices import ALL_DEVICES, CPU_DEVICE, Device
5
5
  from ._flags import get_array_api_strict_flags, requires_api_version
6
6
  from ._typing import Capabilities, DataTypes, DefaultDataTypes
7
7
 
@@ -40,12 +40,7 @@ class __array_namespace_info__:
40
40
  *,
41
41
  device: Device | None = None,
42
42
  ) -> DefaultDataTypes:
43
- return {
44
- "real floating": dt.float64,
45
- "complex floating": dt.complex128,
46
- "integral": dt.int64,
47
- "indexing": dt.int64,
48
- }
43
+ return _devices.get_default_dtypes(device)
49
44
 
50
45
  @requires_api_version('2023.12')
51
46
  def dtypes(
@@ -54,78 +49,21 @@ class __array_namespace_info__:
54
49
  device: Device | None = None,
55
50
  kind: str | tuple[str, ...] | None = None,
56
51
  ) -> DataTypes:
57
- if kind is None:
58
- return {
59
- "bool": dt.bool,
60
- "int8": dt.int8,
61
- "int16": dt.int16,
62
- "int32": dt.int32,
63
- "int64": dt.int64,
64
- "uint8": dt.uint8,
65
- "uint16": dt.uint16,
66
- "uint32": dt.uint32,
67
- "uint64": dt.uint64,
68
- "float32": dt.float32,
69
- "float64": dt.float64,
70
- "complex64": dt.complex64,
71
- "complex128": dt.complex128,
72
- }
73
- if kind == "bool":
74
- return {"bool": dt.bool}
75
- if kind == "signed integer":
76
- return {
77
- "int8": dt.int8,
78
- "int16": dt.int16,
79
- "int32": dt.int32,
80
- "int64": dt.int64,
81
- }
82
- if kind == "unsigned integer":
83
- return {
84
- "uint8": dt.uint8,
85
- "uint16": dt.uint16,
86
- "uint32": dt.uint32,
87
- "uint64": dt.uint64,
88
- }
89
- if kind == "integral":
90
- return {
91
- "int8": dt.int8,
92
- "int16": dt.int16,
93
- "int32": dt.int32,
94
- "int64": dt.int64,
95
- "uint8": dt.uint8,
96
- "uint16": dt.uint16,
97
- "uint32": dt.uint32,
98
- "uint64": dt.uint64,
99
- }
100
- if kind == "real floating":
101
- return {
102
- "float32": dt.float32,
103
- "float64": dt.float64,
104
- }
105
- if kind == "complex floating":
106
- return {
107
- "complex64": dt.complex64,
108
- "complex128": dt.complex128,
109
- }
110
- if kind == "numeric":
111
- return {
112
- "int8": dt.int8,
113
- "int16": dt.int16,
114
- "int32": dt.int32,
115
- "int64": dt.int64,
116
- "uint8": dt.uint8,
117
- "uint16": dt.uint16,
118
- "uint32": dt.uint32,
119
- "uint64": dt.uint64,
120
- "float32": dt.float32,
121
- "float64": dt.float64,
122
- "complex64": dt.complex64,
123
- "complex128": dt.complex128,
124
- }
125
- if isinstance(kind, tuple):
52
+ if device is None:
53
+ device = CPU_DEVICE
54
+ if isinstance(kind, type(None) | str):
55
+
56
+ try:
57
+ dtypes = _devices._kind_to_dtypes[kind]
58
+ except KeyError:
59
+ raise ValueError(f"unsupported kind: {kind!r}")
60
+ res = _devices._map_supported(dtypes, device)
61
+ return res
62
+
63
+ elif isinstance(kind, tuple):
126
64
  res: DataTypes = {}
127
65
  for k in kind:
128
- res.update(self.dtypes(kind=k))
66
+ res.update(self.dtypes(kind=k, device=device))
129
67
  return res
130
68
  raise ValueError(f"unsupported kind: {kind!r}")
131
69
 
@@ -39,7 +39,10 @@ def cumulative_sum(
39
39
  if include_initial:
40
40
  if axis < 0:
41
41
  axis += x.ndim
42
- x = concat([zeros(x.shape[:axis] + (1,) + x.shape[axis + 1:], dtype=x.dtype), x], axis=axis)
42
+ x = concat(
43
+ [zeros(x.shape[:axis] + (1,) + x.shape[axis + 1:], dtype=x.dtype, device=x.device), x],
44
+ axis=axis
45
+ )
43
46
  return Array._new(np.cumsum(x._array, axis=axis, dtype=_np_dtype(dtype)), device=x.device)
44
47
 
45
48
 
@@ -66,7 +69,10 @@ def cumulative_prod(
66
69
  if include_initial:
67
70
  if axis < 0:
68
71
  axis += x.ndim
69
- x = concat([ones(x.shape[:axis] + (1,) + x.shape[axis + 1:], dtype=x.dtype), x], axis=axis)
72
+ x = concat(
73
+ [ones(x.shape[:axis] + (1,) + x.shape[axis + 1:], dtype=x.dtype, device=x.device), x],
74
+ axis=axis
75
+ )
70
76
  return Array._new(np.cumprod(x._array, axis=axis, dtype=_np_dtype(dtype)), device=x.device)
71
77
 
72
78
 
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
28
28
  commit_id: COMMIT_ID
29
29
  __commit_id__: COMMIT_ID
30
30
 
31
- __version__ = version = '2.5'
32
- __version_tuple__ = version_tuple = (2, 5)
31
+ __version__ = version = '2.6'
32
+ __version_tuple__ = version_tuple = (2, 6)
33
33
 
34
34
  __commit_id__ = commit_id = None
@@ -9,7 +9,8 @@ import numpy as np
9
9
  import pytest
10
10
 
11
11
  from .. import ones, arange, reshape, asarray, result_type, all, equal, stack
12
- from .._array_object import Array, CPU_DEVICE, Device
12
+ from .._array_object import Array
13
+ from .._devices import CPU_DEVICE, Device, DLDeviceType
13
14
  from .._dtypes import (
14
15
  _all_dtypes,
15
16
  _boolean_dtypes,
@@ -220,6 +221,14 @@ def test_setitem_invalid_promotions():
220
221
  a[0] = asarray(3.5j, dtype=complex128)
221
222
 
222
223
 
224
+ def test_setitem_device_transfer():
225
+ a = arange(3)
226
+ b = arange(4, 1, -1, device=Device('device1'))
227
+
228
+ with pytest.raises(ValueError):
229
+ a[:] = b[:]
230
+
231
+
223
232
  def test_promoted_scalar_inherits_device():
224
233
  device1 = Device("device1")
225
234
  x = asarray([1., 2, 3], device=device1)
@@ -749,6 +758,40 @@ def test_dlpack_2023_12(api_version):
749
758
  a.__dlpack__(copy=True)
750
759
  a.__dlpack__(copy=None)
751
760
 
761
+ @pytest.mark.parametrize(
762
+ ("device", "expected"),
763
+ [
764
+ (CPU_DEVICE, (DLDeviceType.kDLCPU, 0)),
765
+ (Device("device1"), (DLDeviceType.kDLCUDA, 0)),
766
+ (Device("device2"), (DLDeviceType.kDLCUDA, 1)),
767
+ ],
768
+ )
769
+ def test_dlpack_device_numbers(device, expected):
770
+ a = asarray([1, 2, 3], device=device)
771
+ assert a.__dlpack_device__() == expected
772
+
773
+
774
+ @pytest.mark.parametrize("device", [CPU_DEVICE, Device("device1"), Device("device2")])
775
+ def test_dlpack_export_with_matching_dl_device(device):
776
+ if np.lib.NumpyVersion(np.__version__) < "2.1.0":
777
+ pytest.skip("dl_device argument requires NumPy >= 2.1.0")
778
+ set_array_api_strict_flags(api_version="2023.12")
779
+
780
+ a = asarray([1, 2, 3], device=device)
781
+ a.__dlpack__(dl_device=a.__dlpack_device__())
782
+
783
+
784
+ @pytest.mark.parametrize("device", [Device("device1"), Device("device2")])
785
+ def test_dlpack_cross_device_export_buffer_error(device):
786
+ if np.lib.NumpyVersion(np.__version__) < "2.1.0":
787
+ pytest.skip("dl_device argument requires NumPy >= 2.1.0")
788
+ set_array_api_strict_flags(api_version="2023.12")
789
+
790
+ a = asarray([1, 2, 3], device=device)
791
+ with pytest.raises(BufferError):
792
+ a.__dlpack__(dl_device=(DLDeviceType.kDLCPU, 0), copy=False)
793
+
794
+
752
795
  def test_pickle():
753
796
  """Check that arrays are pickleable (despite raising on `__new__`)"""
754
797
  a = ones(2)
@@ -22,8 +22,10 @@ from .._creation_functions import (
22
22
  zeros,
23
23
  zeros_like,
24
24
  )
25
- from .._dtypes import float32, float64
26
- from .._array_object import Array, CPU_DEVICE, Device
25
+ from .._dtypes import float32, float64, complex64, bool as xp_bool
26
+ from .._array_object import Array
27
+ from .._devices import CPU_DEVICE, ALL_DEVICES, Device
28
+ from .._info import __array_namespace_info__
27
29
  from .._flags import set_array_api_strict_flags
28
30
 
29
31
  def test_asarray_errors():
@@ -212,6 +214,7 @@ def test_zeros_like_errors():
212
214
  assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype=int))
213
215
  assert_raises(ValueError, lambda: zeros_like(asarray(1), dtype="i"))
214
216
 
217
+
215
218
  def test_meshgrid_dtype_errors():
216
219
  # Doesn't raise
217
220
  meshgrid()
@@ -221,6 +224,150 @@ def test_meshgrid_dtype_errors():
221
224
  assert_raises(ValueError, lambda: meshgrid(asarray([1.], dtype=float32), asarray([1.], dtype=float64)))
222
225
 
223
226
 
227
+
228
+ def _full(a, *args, **kwds):
229
+ return full(a, fill_value=42.0, *args, **kwds)
230
+
231
+
232
+ def _full_like(a, *args, **kwds):
233
+ return full_like(a, fill_value=42.0, *args, **kwds)
234
+
235
+
236
+ class TestDefaultDType:
237
+
238
+ info = __array_namespace_info__()
239
+
240
+ @pytest.mark.parametrize("device", ALL_DEVICES)
241
+ @pytest.mark.parametrize("func", [empty, zeros, ones, _full])
242
+ def test_ones_etc(self, func, device):
243
+ a = func(1, device=device)
244
+ assert a.dtype == self.info.default_dtypes(device=device)["real floating"]
245
+
246
+ @pytest.mark.parametrize("func", [empty_like, zeros_like, ones_like, _full_like])
247
+ def test_ones_like_etc_correct(self, func):
248
+ # float32 is preserved
249
+ a = ones(2, dtype=float32)
250
+ device = Device('no_float64')
251
+ b = func(a, device=device)
252
+ assert b.dtype == self.info.default_dtypes(device=device)["real floating"]
253
+ assert b.device == device
254
+
255
+ @pytest.mark.parametrize("func", [empty_like, zeros_like, ones_like, _full_like])
256
+ def test_ones_like_etc_incorrect(self, func):
257
+ a = ones(2)
258
+ assert a.dtype == float64
259
+ assert a.device == Device()
260
+
261
+ # XXX: a.dtype not supported by the device: ValueError or TypeError?
262
+
263
+ # >>> a = torch.ones(3, dtype=torch.float64, device='cpu')
264
+ # >>> torch.ones_like(a, device='mps')
265
+ # TypeError: Cannot convert a MPS Tensor to float64 dtype as the MPS framework
266
+ # doesn't support float64.
267
+
268
+ # incompatible dtype inferred from `a.dtype`
269
+ with pytest.raises((TypeError, ValueError)):
270
+ func(a, device=Device('no_float64'))
271
+
272
+ # `a.dtype` is compatible but the explicit dtype= argument is incompatible
273
+ a = ones(2, dtype=float32)
274
+ with pytest.raises((TypeError, ValueError)):
275
+ func(a, device=Device('no_float64'), dtype=float64)
276
+
277
+ def test_eye(self):
278
+ device = Device('no_float64')
279
+ a = eye(3, device=device)
280
+ assert a.dtype == self.info.default_dtypes(device=device)["real floating"]
281
+ assert a.device == device
282
+
283
+ with pytest.raises((TypeError, ValueError)):
284
+ eye(3, device=device, dtype=float64)
285
+
286
+ def test_linspace(self):
287
+ device = Device('no_float64')
288
+
289
+ a = linspace(1, 10, 11, device=device)
290
+ assert a.dtype == self.info.default_dtypes(device=device)["real floating"]
291
+ assert a.device == device
292
+
293
+ a = linspace(1+0j, 10, 11, device=device)
294
+ assert a.dtype == self.info.default_dtypes(device=device)["complex floating"]
295
+
296
+ with pytest.raises((TypeError, ValueError)):
297
+ linspace(1, 10, 11, device=device, dtype=float64)
298
+
299
+ def test_arange(self):
300
+ device = Device('no_float64')
301
+
302
+ a = arange(0, 10, 1, device=device)
303
+ assert a.dtype == self.info.default_dtypes(device=device)["integral"]
304
+ assert a.device == device
305
+
306
+ a = arange(0.0, 10, 1, device=device)
307
+ assert a.dtype == self.info.default_dtypes(device=device)["real floating"]
308
+ assert a.device == device
309
+
310
+ with pytest.raises((TypeError, ValueError)):
311
+ arange(0, 10, 1, device=device, dtype=float64)
312
+
313
+ with pytest.raises((TypeError, ValueError)):
314
+ arange(0.0, 10, 1, device=device, dtype=float64)
315
+
316
+ def test_asarray(self):
317
+ device = Device('no_float64')
318
+
319
+ ### asarray(python_object)
320
+ for x in (True, [False,]):
321
+ arr = asarray(x, device=device)
322
+ assert arr.dtype == xp_bool
323
+ assert arr.device == device
324
+
325
+ for x in [1, [1,]]:
326
+ arr = asarray(x, device=device)
327
+ assert arr.dtype == self.info.default_dtypes(device=device)['integral']
328
+ assert arr.device == device
329
+
330
+ for x in [1.0, [1.0,]]:
331
+ arr = asarray(x, device=device)
332
+ assert arr.dtype == self.info.default_dtypes(device=device)['real floating']
333
+ assert arr.device == device
334
+
335
+ for x in [1j, [1j,]]:
336
+ arr = asarray(x, device=device)
337
+ assert arr.dtype == self.info.default_dtypes(device=device)['complex floating']
338
+ assert arr.device == device
339
+
340
+ # asarray(python_object, dtype=unsupported_by_device)
341
+ with pytest.raises(ValueError, match="Device"):
342
+ asarray(1, dtype=float64, device=device)
343
+
344
+ ### asarray(array)
345
+
346
+ # compatible dtypes, device transfer
347
+ src = asarray(1, dtype=float32, device=Device('device1'))
348
+ dst = asarray(src, device=device)
349
+ assert dst.device == device
350
+ assert dst.dtype == float32
351
+
352
+ # incompatible dtypes, device transfer
353
+ src = asarray(1, dtype=float64, device=Device('device1'))
354
+
355
+ with pytest.raises(ValueError, match="Device"):
356
+ asarray(src, device=device)
357
+
358
+
359
+ def test_asarray_device_2():
360
+ # device2 allows float64 but defaults to float32
361
+ x = asarray([1.0], device=Device('device2'))
362
+ assert x.dtype == float32
363
+
364
+ x = asarray([1j], device=Device('device2'))
365
+ assert x.dtype == complex64
366
+
367
+ y = asarray([1.0], device=Device('device2'), dtype=float64)
368
+ assert y.dtype == float64
369
+
370
+
224
371
  @pytest.mark.parametrize("api_version", ['2021.12', '2022.12', '2023.12'])
225
372
  def from_dlpack_2023_12(api_version):
226
373
  if api_version != '2022.12':
@@ -247,3 +394,13 @@ def test_from_dlpack_default_device():
247
394
  y = from_dlpack(x)
248
395
  z = from_dlpack(np.asarray([1, 2, 3]))
249
396
  assert x.device == y.device == z.device == CPU_DEVICE
397
+
398
+
399
+ @pytest.mark.parametrize(
400
+ "device",
401
+ [Device("device1"), Device("device2")],
402
+ )
403
+ def test_from_dlpack_preserves_device(device):
404
+ x = asarray([1, 2, 3], device=device)
405
+ y = from_dlpack(x)
406
+ assert y.device == device
@@ -1,6 +1,6 @@
1
1
  import pytest
2
2
 
3
- import array_api_strict
3
+ import array_api_strict as xp
4
4
 
5
5
 
6
6
  @pytest.mark.parametrize(
@@ -18,11 +18,11 @@ import array_api_strict
18
18
  ),
19
19
  )
20
20
  def test_fft_device_support_complex(func_name):
21
- func = getattr(array_api_strict.fft, func_name)
22
- x = array_api_strict.asarray(
21
+ func = getattr(xp.fft, func_name)
22
+ x = xp.asarray(
23
23
  [1, 2.0],
24
- dtype=array_api_strict.complex64,
25
- device=array_api_strict.Device("device1"),
24
+ dtype=xp.complex64,
25
+ device=xp.Device("device1"),
26
26
  )
27
27
  y = func(x)
28
28
 
@@ -31,8 +31,50 @@ def test_fft_device_support_complex(func_name):
31
31
 
32
32
  @pytest.mark.parametrize("func_name", ("rfft", "rfftn", "ihfft"))
33
33
  def test_fft_device_support_real(func_name):
34
- func = getattr(array_api_strict.fft, func_name)
35
- x = array_api_strict.asarray([1, 2.0], device=array_api_strict.Device("device1"))
34
+ func = getattr(xp.fft, func_name)
35
+ x = xp.asarray([1, 2.0], device=xp.Device("device1"))
36
36
  y = func(x)
37
37
 
38
38
  assert x.device == y.device
39
+
40
+
41
+ @pytest.mark.parametrize("func_name", ("fftfreq", "rfftfreq"))
42
+ def test_fft_default_dtype(func_name):
43
+ func = getattr(xp.fft, func_name)
44
+ device = xp.Device("no_float64")
45
+ res = func(3, device=device)
46
+ assert res.device == device
47
+ assert res.dtype == xp.__array_namespace_info__().default_dtypes(device=device)["real floating"]
48
+
49
+ with pytest.raises(ValueError):
50
+ func(3, device=device, dtype=xp.float64)
51
+
52
+
53
+ class TestF32Device:
54
+ @pytest.mark.parametrize("dtype_str", ["float64", "complex128"])
55
+ def test_f64_raises(self, dtype_str):
56
+ f32_only_device = xp.Device("no_float64")
57
+ dtype = getattr(xp, dtype_str)
58
+ with pytest.raises(ValueError):
59
+ xp.arange(3, device=f32_only_device, dtype=dtype)
60
+
61
+ def test_info_no_f64(self):
62
+ f32_only_device = xp.Device("no_float64")
63
+
64
+ info = xp.__array_namespace_info__()
65
+ all_dtypes = info.dtypes(device=f32_only_device)
66
+ assert "float64" not in all_dtypes
67
+ assert "complex128" not in all_dtypes
68
+
69
+ def test_info_default_dtypes(self):
70
+ f32_only_device = xp.Device("no_float64")
71
+ info = xp.__array_namespace_info__()
72
+ defaults = info.default_dtypes(device=f32_only_device)
73
+ assert defaults["real floating"] == xp.float32
74
+ assert defaults["complex floating"] == xp.complex64
75
+
76
+ cpu_device = xp.Device()
77
+ info = xp.__array_namespace_info__()
78
+ defaults = info.default_dtypes(device=cpu_device)
79
+ assert defaults["real floating"] == xp.float64
80
+ assert defaults["complex floating"] == xp.complex128
@@ -6,7 +6,7 @@ import pytest
6
6
 
7
7
 
8
8
  from .. import asarray, _elementwise_functions
9
- from .._array_object import ALL_DEVICES, CPU_DEVICE, Device
9
+ from .._devices import ALL_DEVICES, CPU_DEVICE, Device
10
10
  from .._elementwise_functions import bitwise_left_shift, bitwise_right_shift
11
11
  from .._dtypes import (
12
12
  _dtype_categories,
@@ -21,6 +21,7 @@ from .._dtypes import (
21
21
  int64,
22
22
  uint64,
23
23
  )
24
+ from .._info import __array_namespace_info__
24
25
  from .test_array_object import _check_op_array_scalar, BIG_INT
25
26
 
26
27
  import array_api_strict
@@ -144,6 +145,10 @@ def test_elementwise_function_device_persists(func_name, types, device):
144
145
  yield asarray(1., dtype=dtype, device=device)
145
146
 
146
147
  dtypes = _dtype_categories[types]
148
+
149
+ supported_dtypes = __array_namespace_info__().dtypes(device=device)
150
+ dtypes = [dt for dt in dtypes if dt in supported_dtypes]
151
+
147
152
  func = getattr(_elementwise_functions, func_name)
148
153
 
149
154
  for x in _array_vals(dtypes):
@@ -3,7 +3,7 @@ import pytest
3
3
  import array_api_strict as xp
4
4
 
5
5
  from array_api_strict import ArrayAPIStrictFlags
6
- from .._array_object import ALL_DEVICES, CPU_DEVICE, Device
6
+ from .._devices import ALL_DEVICES, CPU_DEVICE, Device
7
7
  from .._dtypes import _all_dtypes
8
8
 
9
9
 
@@ -55,3 +55,19 @@ def test_mean_complex():
55
55
  with pytest.raises(TypeError):
56
56
  xp.mean(xp.arange(3))
57
57
 
58
+
59
+ def test_cumsum_device():
60
+ x = xp.arange(3, device=xp.Device('device1'))
61
+ y = xp.cumulative_sum(x, include_initial=True)
62
+ expected = xp.asarray([0, 0, 1, 3], device=x.device)
63
+ assert y.device == expected.device
64
+ assert xp.all(y == expected)
65
+
66
+
67
+ def test_cumprod_device():
68
+ x = xp.arange(1, 4, device=xp.Device('device1'))
69
+ y = xp.cumulative_prod(x, include_initial=True)
70
+ expected = xp.asarray([1, 1, 2, 6], device=x.device)
71
+ assert y.device == expected.device
72
+ assert xp.all(y == expected)
73
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: array_api_strict
3
- Version: 2.5
3
+ Version: 2.6
4
4
  Summary: A strict, minimal implementation of the Python array API standard.
5
5
  Author: Consortium for Python Data API Standards
6
6
  License: Copyright (c) 2021-2024, NumPy Developers, Consortium for Python Data API Standards
@@ -1,44 +1,45 @@
1
1
  array_api_strict/__init__.py,sha256=kexXRJ7WHgMTeMi80H6XiObC3ePtUEr5gf92dnwyPGE,7173
2
- array_api_strict/_array_object.py,sha256=m5197OW2aW778dGDMjQI4Zxaw5BfIqXWQ6sJK_DpgaA,54393
2
+ array_api_strict/_array_object.py,sha256=wOCTJl6JaeOqbS1aoH0wbFlfx1vqR6Jzu0U-5w9-Ncw,54938
3
3
  array_api_strict/_constants.py,sha256=ilkAGjIceZxT4zPywIoWbl3Xv8k19UOI4SSF6EPegpg,93
4
- array_api_strict/_creation_functions.py,sha256=TXookrcG1zeUBMvgFdbiwXxZJ1aMvViSef24tqVo53s,12658
4
+ array_api_strict/_creation_functions.py,sha256=1M6WYyTbVHfiFaTYkCZPG-j-dmt6LdifnM9Y4GD_TSo,15100
5
5
  array_api_strict/_data_type_functions.py,sha256=5OPnsIj4QafrSlnizUZcO4DHO5u0ap9OyDNovV4qrns,8765
6
- array_api_strict/_dtypes.py,sha256=PNSd4LpGdnRiEGoB2uqxi93d0dmtiyFp_awUzUcdHJE,6597
6
+ array_api_strict/_devices.py,sha256=k3QdhG2NKGw5DfHAZOvkJ-d_ft1Jn7083D4dXoeETwU,4225
7
+ array_api_strict/_dtypes.py,sha256=ejImxjVLg7-jSKrdKqGDCXZ8oHYKGhdl68WiP9uaIho,6688
7
8
  array_api_strict/_elementwise_functions.py,sha256=D3jOalyR5-kDSzeGTZLKnGPVwjKBuPihkwn23YSxcUc,13198
8
- array_api_strict/_fft.py,sha256=DVw7KK4Xvyf3_0rJuWdskggGRCSxS4OrguYNVBf9fH0,10189
9
+ array_api_strict/_fft.py,sha256=Ut1IgT6lIbpC2g_j2eFejLvW9NpctKuDwdOOJ5luNFE,10971
9
10
  array_api_strict/_flags.py,sha256=JaaGahMa-yQjz9fq2E_cFQvhh5B5rVJKms9pMcwdKAg,14758
10
11
  array_api_strict/_helpers.py,sha256=St8M41s5pdhdPdn1-BcdZCrNtRID4X9z5F28fBD3GNg,1915
11
12
  array_api_strict/_indexing_functions.py,sha256=BHPtoyRUIoEMe28MkwUrHRSz5X71i8w_WkTuWQljrpI,1398
12
- array_api_strict/_info.py,sha256=nGLPkobKqDuLlLD4yOxG4y3JVO98o9UNEImXu6YeKH8,4532
13
+ array_api_strict/_info.py,sha256=U0EgZiPbksc0mcZTALlDx5AnKKUTChc9aR1CQOqFXAg,2551
13
14
  array_api_strict/_linalg.py,sha256=HQjpkVPB0R59mOQBR4cqlZTUKOQTEjGEXbkwk3KNa2Y,21495
14
15
  array_api_strict/_linear_algebra_functions.py,sha256=j8fSBharI31ugZHsUvm74Nv3SHxRrxqtmouK3AOH038,3800
15
16
  array_api_strict/_manipulation_functions.py,sha256=KR0O7bMulglaX0DoqEWpiNK3V25D12mFdsqeq-vm8mg,6935
16
17
  array_api_strict/_searching_functions.py,sha256=X7pT_kuGBpJltpo4MvVYiZdnKr7jgnH1DNtHiHTKdgw,4263
17
18
  array_api_strict/_set_functions.py,sha256=yTKA2OqueeKwk8tp_XcpcsWliL02kgzT3NBzot5zuQ8,4196
18
19
  array_api_strict/_sorting_functions.py,sha256=kw_ns3NajcA8ekpHikNhZxvVePXa3gjdZ7oTwFnBOmk,2074
19
- array_api_strict/_statistical_functions.py,sha256=XR9PoZmxJWTsAbzYj05ytDn2D2YDf2YTzWNApdmJBIM,5642
20
+ array_api_strict/_statistical_functions.py,sha256=MVjoxIvy3eWfWtNXFq6VFMg-Ygmnn9_eixEa8z_EUrc,5744
20
21
  array_api_strict/_typing.py,sha256=FVM2m6ZTZYDnznCo0SlMRpcXxGR49y6k4ejNEiuGUtc,1486
21
22
  array_api_strict/_utility_functions.py,sha256=L7FJM-RT90gqkAqvMEfQ6FkzurTziHByROk_5R8a5fY,1938
22
- array_api_strict/_version.py,sha256=hJiFMfUPM_IAKDdGwMOVrwsdi46DfhTA5ZGiPklON8o,699
23
+ array_api_strict/_version.py,sha256=3bHZCrpqHyLVEDhNiGUyfzQKJwposHttYzrlwruXOpM,699
23
24
  array_api_strict/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
24
25
  array_api_strict/tests/__init__.py,sha256=t_2GZ3lKcsu4ec4GMKPUDYaeMUJyDquBlQAcPgj7kFE,282
25
26
  array_api_strict/tests/conftest.py,sha256=-wIDryl2MdRLdSonU1G1xWssNq2TFKiWuHquNasXYA8,468
26
- array_api_strict/tests/test_array_object.py,sha256=PZj2Ekw6sY1pbNBrjs2Ll3COkGRVXNsROxirpHfXHJ4,29186
27
- array_api_strict/tests/test_creation_functions.py,sha256=KeBxgG65ZnKBwclNFZBjyoSwov3j-E3f9iMnXfUsmA8,8638
27
+ array_api_strict/tests/test_array_object.py,sha256=65VpWqlYnEgfiNJRM2v2grYwK-iEK6rAAju3pPmQGUY,30624
28
+ array_api_strict/tests/test_creation_functions.py,sha256=g4WXz-L5zYKGTG658oqpWtINW9UoSyaeD5IZLuq3vWk,14088
28
29
  array_api_strict/tests/test_data_type_functions.py,sha256=6V7YeJavgsBmKtR1gvY1GTTlKzGyzPAHki1WtKFeVdU,4098
29
- array_api_strict/tests/test_device_support.py,sha256=zpfhHxeRREoXfp0qZTlilm2ZceBc71uCKea1GMVe-ZU,855
30
- array_api_strict/tests/test_elementwise_functions.py,sha256=ZZOfPaCNIug026zv9IdhV2164jZZkRSwmteAnefFBGw,11396
30
+ array_api_strict/tests/test_device_support.py,sha256=f3_OyYRMX9PPVQOOPsti9q5qgBGNyG86QxvgWdF_KPg,2361
31
+ array_api_strict/tests/test_elementwise_functions.py,sha256=4zzXA7b5NmZnWV4aKxsVjJWdLEZV8X9Zw1UFaKMeEII,11571
31
32
  array_api_strict/tests/test_flags.py,sha256=g7Tajftvmc2ih0a6U57FxcpmleEiDoMgCvzUt2S7MF4,18982
32
33
  array_api_strict/tests/test_indexing_functions.py,sha256=C23FnuowVDC1OBuDH06pvsd61qM2dTpTwzw6UgC4BoY,1281
33
34
  array_api_strict/tests/test_linalg.py,sha256=CJ4JnCkWyysMUAih3PI-ZZeOH-X39H0p-RKBoEwk6Jw,5675
34
35
  array_api_strict/tests/test_manipulation_functions.py,sha256=Yc92IvA3FaTZueqAUOFMkx3MH4PXCHDof7ckrJxudQs,1078
35
- array_api_strict/tests/test_searching_functions.py,sha256=wT2VsKwBhyy233pZ2NcXMl_A8vnU1TuevbOwI4eHLF8,3441
36
+ array_api_strict/tests/test_searching_functions.py,sha256=sTOvPUrmzOKbJZDTm_fMecvPpkVJObwZOg-454-j7Cw,3436
36
37
  array_api_strict/tests/test_set_functions.py,sha256=ikzab1j3SXxGf0OqwHrOAM13HwQetdhtB60Zc_gc1DE,542
37
38
  array_api_strict/tests/test_sorting_functions.py,sha256=1xvQBKts5KTKYc-puMITX9iR_KTbzzVB8fY-SObad_Y,899
38
- array_api_strict/tests/test_statistical_functions.py,sha256=0ihnw4W9vOqU6RMBOUw29Fg-xumXpfz0h05v0E0RsMQ,1814
39
+ array_api_strict/tests/test_statistical_functions.py,sha256=c542tcGuxUQvjd8ML1U8I07UFuOhba19804-_-IC2Jc,2335
39
40
  array_api_strict/tests/test_validation.py,sha256=VDci4SgcAhxzSFVnFYBvJWXEsWRxHARnq9TwTfH02xg,635
40
- array_api_strict-2.5.dist-info/LICENSE,sha256=djDm4UfHAJmycwFUNyUmrTdRkrFF9Ac8uqIlbxH7j5Y,1585
41
- array_api_strict-2.5.dist-info/METADATA,sha256=0sP5kLahxH406PSNEXzGLED-PAWJEWZ9QV1EUg6asr4,3613
42
- array_api_strict-2.5.dist-info/WHEEL,sha256=5Mi1sN9lKoFv_gxcPtisEVrJZihrm_beibeg5R6xb4I,91
43
- array_api_strict-2.5.dist-info/top_level.txt,sha256=M4cE8VLgRHp_d9TPkbk7_I4JriELFdEJz-NKJJqAkAE,17
44
- array_api_strict-2.5.dist-info/RECORD,,
41
+ array_api_strict-2.6.dist-info/LICENSE,sha256=djDm4UfHAJmycwFUNyUmrTdRkrFF9Ac8uqIlbxH7j5Y,1585
42
+ array_api_strict-2.6.dist-info/METADATA,sha256=pwiqnybdKy12HJOL3jhV4oH_lbO66EvsekvSaeCCW8E,3613
43
+ array_api_strict-2.6.dist-info/WHEEL,sha256=5Mi1sN9lKoFv_gxcPtisEVrJZihrm_beibeg5R6xb4I,91
44
+ array_api_strict-2.6.dist-info/top_level.txt,sha256=M4cE8VLgRHp_d9TPkbk7_I4JriELFdEJz-NKJJqAkAE,17
45
+ array_api_strict-2.6.dist-info/RECORD,,