array-api-strict 2.0__py3-none-any.whl → 2.1__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.
Files changed (34) hide show
  1. array_api_strict/__init__.py +3 -0
  2. array_api_strict/_array_object.py +129 -53
  3. array_api_strict/_creation_functions.py +37 -21
  4. array_api_strict/_data_type_functions.py +5 -3
  5. array_api_strict/_dtypes.py +1 -1
  6. array_api_strict/_elementwise_functions.py +133 -67
  7. array_api_strict/_fft.py +17 -17
  8. array_api_strict/_flags.py +19 -10
  9. array_api_strict/_indexing_functions.py +3 -1
  10. array_api_strict/_info.py +2 -2
  11. array_api_strict/_linalg.py +31 -20
  12. array_api_strict/_linear_algebra_functions.py +13 -4
  13. array_api_strict/_manipulation_functions.py +28 -13
  14. array_api_strict/_searching_functions.py +13 -5
  15. array_api_strict/_set_functions.py +8 -7
  16. array_api_strict/_sorting_functions.py +2 -2
  17. array_api_strict/_statistical_functions.py +8 -8
  18. array_api_strict/_typing.py +2 -2
  19. array_api_strict/_utility_functions.py +2 -2
  20. array_api_strict/_version.py +3 -3
  21. array_api_strict/tests/test_array_object.py +24 -8
  22. array_api_strict/tests/test_device_support.py +38 -0
  23. array_api_strict/tests/test_elementwise_functions.py +73 -7
  24. array_api_strict/tests/test_flags.py +57 -48
  25. array_api_strict/tests/test_indexing_functions.py +20 -0
  26. array_api_strict/tests/test_linalg.py +14 -13
  27. array_api_strict/tests/test_sorting_functions.py +14 -0
  28. array_api_strict/tests/test_statistical_functions.py +15 -5
  29. {array_api_strict-2.0.dist-info → array_api_strict-2.1.dist-info}/METADATA +1 -5
  30. array_api_strict-2.1.dist-info/RECORD +41 -0
  31. {array_api_strict-2.0.dist-info → array_api_strict-2.1.dist-info}/WHEEL +1 -1
  32. array_api_strict-2.0.dist-info/RECORD +0 -40
  33. {array_api_strict-2.0.dist-info → array_api_strict-2.1.dist-info}/LICENSE +0 -0
  34. {array_api_strict-2.0.dist-info → array_api_strict-2.1.dist-info}/top_level.txt +0 -0
@@ -32,9 +32,12 @@ def _supports_buffer_protocol(obj):
32
32
  def _check_device(device):
33
33
  # _array_object imports in this file are inside the functions to avoid
34
34
  # circular imports
35
- from ._array_object import CPU_DEVICE
35
+ from ._array_object import Device, ALL_DEVICES
36
36
 
37
- if device not in [CPU_DEVICE, None]:
37
+ if device is not None and not isinstance(device, Device):
38
+ raise ValueError(f"Unsupported device {device!r}")
39
+
40
+ if device is not None and device not in ALL_DEVICES:
38
41
  raise ValueError(f"Unsupported device {device!r}")
39
42
 
40
43
  def asarray(
@@ -76,10 +79,10 @@ def asarray(
76
79
  new_array = np.array(obj._array, copy=copy, dtype=_np_dtype)
77
80
  if new_array is not obj._array:
78
81
  raise ValueError("Unable to avoid copy while creating an array from given array.")
79
- return Array._new(new_array)
82
+ return Array._new(new_array, device=device)
80
83
  elif _supports_buffer_protocol(obj):
81
84
  # Buffer protocol will always support no-copy
82
- return Array._new(np.array(obj, copy=copy, dtype=_np_dtype))
85
+ return Array._new(np.array(obj, copy=copy, dtype=_np_dtype), device=device)
83
86
  else:
84
87
  # No-copy is unsupported for Python built-in types.
85
88
  raise ValueError("Unable to avoid copy while creating an array from given object.")
@@ -89,13 +92,13 @@ def asarray(
89
92
  copy = False
90
93
 
91
94
  if isinstance(obj, Array):
92
- return Array._new(np.array(obj._array, copy=copy, dtype=_np_dtype))
95
+ return Array._new(np.array(obj._array, copy=copy, dtype=_np_dtype), device=device)
93
96
  if dtype is None and isinstance(obj, int) and (obj > 2 ** 64 or obj < -(2 ** 63)):
94
97
  # Give a better error message in this case. NumPy would convert this
95
98
  # to an object array. TODO: This won't handle large integers in lists.
96
99
  raise OverflowError("Integer out of bounds for array dtypes")
97
100
  res = np.array(obj, dtype=_np_dtype, copy=copy)
98
- return Array._new(res)
101
+ return Array._new(res, device=device)
99
102
 
100
103
 
101
104
  def arange(
@@ -119,7 +122,7 @@ def arange(
119
122
 
120
123
  if dtype is not None:
121
124
  dtype = dtype._np_dtype
122
- return Array._new(np.arange(start, stop=stop, step=step, dtype=dtype))
125
+ return Array._new(np.arange(start, stop=stop, step=step, dtype=dtype), device=device)
123
126
 
124
127
 
125
128
  def empty(
@@ -140,7 +143,7 @@ def empty(
140
143
 
141
144
  if dtype is not None:
142
145
  dtype = dtype._np_dtype
143
- return Array._new(np.empty(shape, dtype=dtype))
146
+ return Array._new(np.empty(shape, dtype=dtype), device=device)
144
147
 
145
148
 
146
149
  def empty_like(
@@ -158,7 +161,7 @@ def empty_like(
158
161
 
159
162
  if dtype is not None:
160
163
  dtype = dtype._np_dtype
161
- return Array._new(np.empty_like(x._array, dtype=dtype))
164
+ return Array._new(np.empty_like(x._array, dtype=dtype), device=device)
162
165
 
163
166
 
164
167
  def eye(
@@ -182,7 +185,7 @@ def eye(
182
185
 
183
186
  if dtype is not None:
184
187
  dtype = dtype._np_dtype
185
- return Array._new(np.eye(n_rows, M=n_cols, k=k, dtype=dtype))
188
+ return Array._new(np.eye(n_rows, M=n_cols, k=k, dtype=dtype), device=device)
186
189
 
187
190
 
188
191
  _default = object()
@@ -208,7 +211,7 @@ def from_dlpack(
208
211
  if copy not in [_default, None]:
209
212
  raise NotImplementedError("The copy argument to from_dlpack is not yet implemented")
210
213
 
211
- return Array._new(np.from_dlpack(x))
214
+ return Array._new(np.from_dlpack(x), device=device)
212
215
 
213
216
 
214
217
  def full(
@@ -237,7 +240,7 @@ def full(
237
240
  # This will happen if the fill value is not something that NumPy
238
241
  # coerces to one of the acceptable dtypes.
239
242
  raise TypeError("Invalid input to full")
240
- return Array._new(res)
243
+ return Array._new(res, device=device)
241
244
 
242
245
 
243
246
  def full_like(
@@ -265,7 +268,7 @@ def full_like(
265
268
  # This will happen if the fill value is not something that NumPy
266
269
  # coerces to one of the acceptable dtypes.
267
270
  raise TypeError("Invalid input to full_like")
268
- return Array._new(res)
271
+ return Array._new(res, device=device)
269
272
 
270
273
 
271
274
  def linspace(
@@ -290,7 +293,7 @@ def linspace(
290
293
 
291
294
  if dtype is not None:
292
295
  dtype = dtype._np_dtype
293
- return Array._new(np.linspace(start, stop, num, dtype=dtype, endpoint=endpoint))
296
+ return Array._new(np.linspace(start, stop, num, dtype=dtype, endpoint=endpoint), device=device)
294
297
 
295
298
 
296
299
  def meshgrid(*arrays: Array, indexing: str = "xy") -> List[Array]:
@@ -307,8 +310,17 @@ def meshgrid(*arrays: Array, indexing: str = "xy") -> List[Array]:
307
310
  if len({a.dtype for a in arrays}) > 1:
308
311
  raise ValueError("meshgrid inputs must all have the same dtype")
309
312
 
313
+ if len({a.device for a in arrays}) > 1:
314
+ raise ValueError("meshgrid inputs must all be on the same device")
315
+
316
+ # arrays is allowed to be empty
317
+ if arrays:
318
+ device = arrays[0].device
319
+ else:
320
+ device = None
321
+
310
322
  return [
311
- Array._new(array)
323
+ Array._new(array, device=device)
312
324
  for array in np.meshgrid(*[a._array for a in arrays], indexing=indexing)
313
325
  ]
314
326
 
@@ -331,7 +343,7 @@ def ones(
331
343
 
332
344
  if dtype is not None:
333
345
  dtype = dtype._np_dtype
334
- return Array._new(np.ones(shape, dtype=dtype))
346
+ return Array._new(np.ones(shape, dtype=dtype), device=device)
335
347
 
336
348
 
337
349
  def ones_like(
@@ -346,10 +358,12 @@ def ones_like(
346
358
 
347
359
  _check_valid_dtype(dtype)
348
360
  _check_device(device)
361
+ if device is None:
362
+ device = x.device
349
363
 
350
364
  if dtype is not None:
351
365
  dtype = dtype._np_dtype
352
- return Array._new(np.ones_like(x._array, dtype=dtype))
366
+ return Array._new(np.ones_like(x._array, dtype=dtype), device=device)
353
367
 
354
368
 
355
369
  def tril(x: Array, /, *, k: int = 0) -> Array:
@@ -363,7 +377,7 @@ def tril(x: Array, /, *, k: int = 0) -> Array:
363
377
  if x.ndim < 2:
364
378
  # Note: Unlike np.tril, x must be at least 2-D
365
379
  raise ValueError("x must be at least 2-dimensional for tril")
366
- return Array._new(np.tril(x._array, k=k))
380
+ return Array._new(np.tril(x._array, k=k), device=x.device)
367
381
 
368
382
 
369
383
  def triu(x: Array, /, *, k: int = 0) -> Array:
@@ -377,7 +391,7 @@ def triu(x: Array, /, *, k: int = 0) -> Array:
377
391
  if x.ndim < 2:
378
392
  # Note: Unlike np.triu, x must be at least 2-D
379
393
  raise ValueError("x must be at least 2-dimensional for triu")
380
- return Array._new(np.triu(x._array, k=k))
394
+ return Array._new(np.triu(x._array, k=k), device=x.device)
381
395
 
382
396
 
383
397
  def zeros(
@@ -398,7 +412,7 @@ def zeros(
398
412
 
399
413
  if dtype is not None:
400
414
  dtype = dtype._np_dtype
401
- return Array._new(np.zeros(shape, dtype=dtype))
415
+ return Array._new(np.zeros(shape, dtype=dtype), device=device)
402
416
 
403
417
 
404
418
  def zeros_like(
@@ -413,7 +427,9 @@ def zeros_like(
413
427
 
414
428
  _check_valid_dtype(dtype)
415
429
  _check_device(device)
430
+ if device is None:
431
+ device = x.device
416
432
 
417
433
  if dtype is not None:
418
434
  dtype = dtype._np_dtype
419
- return Array._new(np.zeros_like(x._array, dtype=dtype))
435
+ return Array._new(np.zeros_like(x._array, dtype=dtype), device=device)
@@ -37,10 +37,12 @@ def astype(
37
37
  _check_device(device)
38
38
  else:
39
39
  raise TypeError("The device argument to astype requires at least version 2023.12 of the array API")
40
+ else:
41
+ device = x.device
40
42
 
41
43
  if not copy and dtype == x.dtype:
42
44
  return x
43
- return Array._new(x._array.astype(dtype=dtype._np_dtype, copy=copy))
45
+ return Array._new(x._array.astype(dtype=dtype._np_dtype, copy=copy), device=device)
44
46
 
45
47
 
46
48
  def broadcast_arrays(*arrays: Array) -> List[Array]:
@@ -52,7 +54,7 @@ def broadcast_arrays(*arrays: Array) -> List[Array]:
52
54
  from ._array_object import Array
53
55
 
54
56
  return [
55
- Array._new(array) for array in np.broadcast_arrays(*[a._array for a in arrays])
57
+ Array._new(array, device=arrays[0].device) for array in np.broadcast_arrays(*[a._array for a in arrays])
56
58
  ]
57
59
 
58
60
 
@@ -64,7 +66,7 @@ def broadcast_to(x: Array, /, shape: Tuple[int, ...]) -> Array:
64
66
  """
65
67
  from ._array_object import Array
66
68
 
67
- return Array._new(np.broadcast_to(x._array, shape))
69
+ return Array._new(np.broadcast_to(x._array, shape), device=x.device)
68
70
 
69
71
 
70
72
  def can_cast(from_: Union[Dtype, Array], to: Dtype, /) -> bool:
@@ -121,7 +121,7 @@ _dtype_categories = {
121
121
  "integer": _integer_dtypes,
122
122
  "integer or boolean": _integer_or_boolean_dtypes,
123
123
  "boolean": _boolean_dtypes,
124
- "real floating-point": _floating_dtypes,
124
+ "real floating-point": _real_floating_dtypes,
125
125
  "complex floating-point": _complex_floating_dtypes,
126
126
  "floating-point": _floating_dtypes,
127
127
  }