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.
Files changed (35) hide show
  1. array_api_strict/__init__.py +11 -5
  2. array_api_strict/_array_object.py +226 -200
  3. array_api_strict/_constants.py +1 -1
  4. array_api_strict/_creation_functions.py +97 -119
  5. array_api_strict/_data_type_functions.py +73 -64
  6. array_api_strict/_dtypes.py +35 -24
  7. array_api_strict/_elementwise_functions.py +138 -482
  8. array_api_strict/_fft.py +28 -32
  9. array_api_strict/_flags.py +65 -26
  10. array_api_strict/_helpers.py +23 -14
  11. array_api_strict/_indexing_functions.py +3 -8
  12. array_api_strict/_info.py +64 -69
  13. array_api_strict/_linalg.py +57 -53
  14. array_api_strict/_linear_algebra_functions.py +11 -9
  15. array_api_strict/_manipulation_functions.py +30 -30
  16. array_api_strict/_searching_functions.py +22 -33
  17. array_api_strict/_set_functions.py +4 -6
  18. array_api_strict/_sorting_functions.py +6 -6
  19. array_api_strict/_statistical_functions.py +57 -64
  20. array_api_strict/_typing.py +30 -50
  21. array_api_strict/_utility_functions.py +11 -13
  22. array_api_strict/_version.py +2 -2
  23. array_api_strict/py.typed +0 -0
  24. array_api_strict/tests/test_array_object.py +163 -56
  25. array_api_strict/tests/test_creation_functions.py +14 -12
  26. array_api_strict/tests/test_data_type_functions.py +40 -6
  27. array_api_strict/tests/test_elementwise_functions.py +94 -45
  28. array_api_strict/tests/test_searching_functions.py +79 -1
  29. array_api_strict/tests/test_validation.py +1 -3
  30. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/METADATA +5 -4
  31. array_api_strict-2.4.dist-info/RECORD +44 -0
  32. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/WHEEL +1 -1
  33. array_api_strict-2.3.dist-info/RECORD +0 -43
  34. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/LICENSE +0 -0
  35. {array_api_strict-2.3.dist-info → array_api_strict-2.4.dist-info}/top_level.txt +0 -0
@@ -1,51 +1,49 @@
1
- from __future__ import annotations
1
+ from collections.abc import Callable
2
+ from functools import wraps
3
+ from types import NoneType
2
4
 
5
+ import numpy as np
6
+
7
+ from ._array_object import Array
8
+ from ._creation_functions import asarray
9
+ from ._data_type_functions import broadcast_to, iinfo
3
10
  from ._dtypes import (
4
- _boolean_dtypes,
5
- _floating_dtypes,
6
- _real_floating_dtypes,
7
11
  _complex_floating_dtypes,
12
+ _dtype_categories,
8
13
  _integer_dtypes,
9
- _integer_or_boolean_dtypes,
10
- _real_numeric_dtypes,
11
14
  _numeric_dtypes,
15
+ _real_floating_dtypes,
16
+ _real_numeric_dtypes,
12
17
  _result_type,
13
- _dtype_categories,
14
18
  )
15
- from ._array_object import Array
16
19
  from ._flags import requires_api_version
17
- from ._creation_functions import asarray
18
- from ._data_type_functions import broadcast_to, iinfo
19
20
  from ._helpers import _maybe_normalize_py_scalars
20
21
 
21
- from typing import Optional, Union
22
-
23
- import numpy as np
24
-
25
22
 
26
23
  def _binary_ufunc_proto(x1, x2, dtype_category, func_name, np_func):
27
24
  """Base implementation of a binary function, `func_name`, defined for
28
- dtypes from `dtype_category`
25
+ dtypes from `dtype_category`
29
26
  """
30
27
  x1, x2 = _maybe_normalize_py_scalars(x1, x2, dtype_category, func_name)
31
28
 
32
29
  if x1.device != x2.device:
33
- raise ValueError(f"Arrays from two different devices ({x1.device} and {x2.device}) can not be combined.")
30
+ raise ValueError(
31
+ f"Arrays from two different devices ({x1.device} and {x2.device}) can not be combined."
32
+ )
34
33
  # Call result type here just to raise on disallowed type combinations
35
34
  _result_type(x1.dtype, x2.dtype)
36
35
  x1, x2 = Array._normalize_two_args(x1, x2)
37
36
  return Array._new(np_func(x1._array, x2._array), device=x1.device)
38
37
 
39
38
 
40
- _binary_docstring_template=\
41
- """
39
+ _docstring_template = """
42
40
  Array API compatible wrapper for :py:func:`np.%s <numpy.%s>`.
43
41
 
44
42
  See its docstring for more information.
45
43
  """
46
44
 
47
45
 
48
- def create_binary_func(func_name, dtype_category, np_func):
46
+ def _create_binary_func(func_name, dtype_category, np_func):
49
47
  def inner(x1, x2, /) -> Array:
50
48
  return _binary_ufunc_proto(x1, x2, dtype_category, func_name, np_func)
51
49
  return inner
@@ -54,15 +52,15 @@ def create_binary_func(func_name, dtype_category, np_func):
54
52
  # static type annotation for ArrayOrPythonScalar arguments given a category
55
53
  # NB: keep the keys in sync with the _dtype_categories dict
56
54
  _annotations = {
57
- "all": "bool | int | float | complex | Array",
58
- "real numeric": "int | float | Array",
59
- "numeric": "int | float | complex | Array",
55
+ "all": "complex | Array",
56
+ "real numeric": "float | Array",
57
+ "numeric": "complex | Array",
60
58
  "integer": "int | Array",
61
- "integer or boolean": "int | bool | Array",
59
+ "integer or boolean": "int | Array",
62
60
  "boolean": "bool | Array",
63
61
  "real floating-point": "float | Array",
64
62
  "complex floating-point": "complex | Array",
65
- "floating-point": "float | complex | Array",
63
+ "floating-point": "complex | Array",
66
64
  }
67
65
 
68
66
 
@@ -75,7 +73,7 @@ _binary_funcs = {
75
73
  "bitwise_xor": "integer or boolean",
76
74
  "_bitwise_left_shift": "integer", # leading underscore deliberate
77
75
  "_bitwise_right_shift": "integer",
78
- # XXX: copysign: real fp or numeric?
76
+ # XXX: copysign: real fp or numeric?
79
77
  "copysign": "real floating-point",
80
78
  "divide": "floating-point",
81
79
  "equal": "all",
@@ -105,7 +103,7 @@ _numpy_renames = {
105
103
  "atan2": "arctan2",
106
104
  "_bitwise_left_shift": "left_shift",
107
105
  "_bitwise_right_shift": "right_shift",
108
- "pow": "power"
106
+ "pow": "power",
109
107
  }
110
108
 
111
109
 
@@ -117,10 +115,10 @@ for func_name, dtype_category in _binary_funcs.items():
117
115
  numpy_name = _numpy_renames.get(func_name, func_name)
118
116
  np_func = getattr(np, numpy_name)
119
117
 
120
- func = create_binary_func(func_name, dtype_category, np_func)
118
+ func = _create_binary_func(func_name, dtype_category, np_func)
121
119
  func.__name__ = func_name
122
120
 
123
- func.__doc__ = _binary_docstring_template % (numpy_name, numpy_name)
121
+ func.__doc__ = _docstring_template % (numpy_name, numpy_name)
124
122
  func.__annotations__['x1'] = _annotations[dtype_category]
125
123
  func.__annotations__['x2'] = _annotations[dtype_category]
126
124
 
@@ -153,168 +151,137 @@ if _bitwise_right_shift.__doc__: # noqa: F821
153
151
 
154
152
 
155
153
  # clean up to not pollute the namespace
156
- del func, create_binary_func
157
-
158
-
159
- def abs(x: Array, /) -> Array:
160
- """
161
- Array API compatible wrapper for :py:func:`np.abs <numpy.abs>`.
162
-
163
- See its docstring for more information.
164
- """
165
- if x.dtype not in _numeric_dtypes:
166
- raise TypeError("Only numeric dtypes are allowed in abs")
167
- return Array._new(np.abs(x._array), device=x.device)
154
+ del func, _create_binary_func
155
+
156
+
157
+ def _create_unary_func(
158
+ func_name: str,
159
+ dtype_category: str,
160
+ np_func_name: str | None = None,
161
+ ) -> Callable[[Array], Array]:
162
+ allowed_dtypes = _dtype_categories[dtype_category]
163
+ np_func_name = np_func_name or func_name
164
+ np_func = getattr(np, np_func_name)
165
+
166
+ def func(x: Array, /) -> Array:
167
+ if not isinstance(x, Array):
168
+ raise TypeError(f"Only Array objects are allowed; got {type(x)}")
169
+ if x.dtype not in allowed_dtypes:
170
+ raise TypeError(
171
+ f"Only {dtype_category} dtypes are allowed in {func_name}; "
172
+ f"got {x.dtype}."
173
+ )
174
+ return Array._new(np_func(x._array), device=x.device)
168
175
 
176
+ func.__name__ = func_name
177
+ func.__doc__ = _docstring_template % (np_func_name, np_func_name)
178
+ return func
179
+
180
+
181
+ def _identity_if_integer(func: Callable[[Array], Array]) -> Callable[[Array], Array]:
182
+ """Hack around NumPy 1.x behaviour for ceil, floor, and trunc
183
+ vs. integer inputs
184
+ """
185
+
186
+ @wraps(func)
187
+ def wrapper(x: Array, /) -> Array:
188
+ if isinstance(x, Array) and x.dtype in _integer_dtypes:
189
+ return x
190
+ return func(x)
191
+
192
+ return wrapper
193
+
194
+
195
+ abs = _create_unary_func("abs", "numeric")
196
+ acos = _create_unary_func("acos", "floating-point", "arccos")
197
+ acosh = _create_unary_func("acosh", "floating-point", "arccosh")
198
+ asin = _create_unary_func("asin", "floating-point", "arcsin")
199
+ asinh = _create_unary_func("asinh", "floating-point", "arcsinh")
200
+ atan = _create_unary_func("atan", "floating-point", "arctan")
201
+ atanh = _create_unary_func("atanh", "floating-point", "arctanh")
202
+ bitwise_invert = _create_unary_func("bitwise_invert", "integer or boolean", "invert")
203
+ ceil = _identity_if_integer(_create_unary_func("ceil", "real numeric"))
204
+ conj = _create_unary_func("conj", "numeric")
205
+ cos = _create_unary_func("cos", "floating-point", "cos")
206
+ cosh = _create_unary_func("cosh", "floating-point", "cosh")
207
+ exp = _create_unary_func("exp", "floating-point")
208
+ expm1 = _create_unary_func("expm1", "floating-point")
209
+ floor = _identity_if_integer(_create_unary_func("floor", "real numeric"))
210
+ imag = _create_unary_func("imag", "complex floating-point")
211
+ isfinite = _create_unary_func("isfinite", "numeric")
212
+ isinf = _create_unary_func("isinf", "numeric")
213
+ isnan = _create_unary_func("isnan", "numeric")
214
+ log = _create_unary_func("log", "floating-point")
215
+ log10 = _create_unary_func("log10", "floating-point")
216
+ log1p = _create_unary_func("log1p", "floating-point")
217
+ log2 = _create_unary_func("log2", "floating-point")
218
+ logical_not = _create_unary_func("logical_not", "boolean")
219
+ negative = _create_unary_func("negative", "numeric")
220
+ positive = _create_unary_func("positive", "numeric")
221
+ real = _create_unary_func("real", "numeric")
222
+ reciprocal = requires_api_version("2024.12")(
223
+ _create_unary_func("reciprocal", "floating-point")
224
+ )
225
+ round = _create_unary_func("round", "numeric")
226
+ signbit = requires_api_version("2023.12")(
227
+ _create_unary_func("signbit", "real floating-point")
228
+ )
229
+ sin = _create_unary_func("sin", "floating-point")
230
+ sinh = _create_unary_func("sinh", "floating-point")
231
+ sqrt = _create_unary_func("sqrt", "floating-point")
232
+ square = _create_unary_func("square", "numeric")
233
+ tan = _create_unary_func("tan", "floating-point")
234
+ tanh = _create_unary_func("tanh", "floating-point")
235
+ trunc = _identity_if_integer(_create_unary_func("trunc", "real numeric"))
169
236
 
170
- # Note: the function name is different here
171
- def acos(x: Array, /) -> Array:
172
- """
173
- Array API compatible wrapper for :py:func:`np.arccos <numpy.arccos>`.
174
-
175
- See its docstring for more information.
176
- """
177
- if x.dtype not in _floating_dtypes:
178
- raise TypeError("Only floating-point dtypes are allowed in acos")
179
- return Array._new(np.arccos(x._array), device=x.device)
180
-
181
-
182
- # Note: the function name is different here
183
- def acosh(x: Array, /) -> Array:
184
- """
185
- Array API compatible wrapper for :py:func:`np.arccosh <numpy.arccosh>`.
186
-
187
- See its docstring for more information.
188
- """
189
- if x.dtype not in _floating_dtypes:
190
- raise TypeError("Only floating-point dtypes are allowed in acosh")
191
- return Array._new(np.arccosh(x._array), device=x.device)
192
-
193
-
194
- # Note: the function name is different here
195
- def asin(x: Array, /) -> Array:
196
- """
197
- Array API compatible wrapper for :py:func:`np.arcsin <numpy.arcsin>`.
198
-
199
- See its docstring for more information.
200
- """
201
- if x.dtype not in _floating_dtypes:
202
- raise TypeError("Only floating-point dtypes are allowed in asin")
203
- return Array._new(np.arcsin(x._array), device=x.device)
204
-
205
-
206
- # Note: the function name is different here
207
- def asinh(x: Array, /) -> Array:
208
- """
209
- Array API compatible wrapper for :py:func:`np.arcsinh <numpy.arcsinh>`.
210
-
211
- See its docstring for more information.
212
- """
213
- if x.dtype not in _floating_dtypes:
214
- raise TypeError("Only floating-point dtypes are allowed in asinh")
215
- return Array._new(np.arcsinh(x._array), device=x.device)
216
-
217
-
218
- # Note: the function name is different here
219
- def atan(x: Array, /) -> Array:
220
- """
221
- Array API compatible wrapper for :py:func:`np.arctan <numpy.arctan>`.
222
-
223
- See its docstring for more information.
224
- """
225
- if x.dtype not in _floating_dtypes:
226
- raise TypeError("Only floating-point dtypes are allowed in atan")
227
- return Array._new(np.arctan(x._array), device=x.device)
228
-
229
-
230
- # Note: the function name is different here
231
- def atanh(x: Array, /) -> Array:
232
- """
233
- Array API compatible wrapper for :py:func:`np.arctanh <numpy.arctanh>`.
234
-
235
- See its docstring for more information.
236
- """
237
- if x.dtype not in _floating_dtypes:
238
- raise TypeError("Only floating-point dtypes are allowed in atanh")
239
- return Array._new(np.arctanh(x._array), device=x.device)
240
-
241
-
242
- # Note: the function name is different here
243
- def bitwise_invert(x: Array, /) -> Array:
244
- """
245
- Array API compatible wrapper for :py:func:`np.invert <numpy.invert>`.
246
-
247
- See its docstring for more information.
248
- """
249
- if x.dtype not in _integer_or_boolean_dtypes:
250
- raise TypeError("Only integer or boolean dtypes are allowed in bitwise_invert")
251
- return Array._new(np.invert(x._array), device=x.device)
252
-
253
-
254
- def ceil(x: Array, /) -> Array:
255
- """
256
- Array API compatible wrapper for :py:func:`np.ceil <numpy.ceil>`.
257
-
258
- See its docstring for more information.
259
- """
260
- if x.dtype not in _real_numeric_dtypes:
261
- raise TypeError("Only real numeric dtypes are allowed in ceil")
262
- if x.dtype in _integer_dtypes:
263
- # Note: The return dtype of ceil is the same as the input
264
- return x
265
- return Array._new(np.ceil(x._array), device=x.device)
266
-
267
- # WARNING: This function is not yet tested by the array-api-tests test suite.
268
237
 
269
238
  # Note: min and max argument names are different and not optional in numpy.
270
239
  @requires_api_version('2023.12')
271
240
  def clip(
272
241
  x: Array,
273
242
  /,
274
- min: Optional[Union[int, float, Array]] = None,
275
- max: Optional[Union[int, float, Array]] = None,
243
+ min: Array | float | None = None,
244
+ max: Array | float | None = None,
276
245
  ) -> Array:
277
246
  """
278
247
  Array API compatible wrapper for :py:func:`np.clip <numpy.clip>`.
279
248
 
280
249
  See its docstring for more information.
281
250
  """
282
- if isinstance(min, Array) and x.device != min.device:
283
- raise ValueError(f"Arrays from two different devices ({x.device} and {min.device}) can not be combined.")
284
- if isinstance(max, Array) and x.device != max.device:
285
- raise ValueError(f"Arrays from two different devices ({x.device} and {max.device}) can not be combined.")
251
+ if not isinstance(x, Array):
252
+ raise TypeError(f"Only Array objects are allowed; got {type(x)}")
286
253
 
287
254
  if (x.dtype not in _real_numeric_dtypes
288
255
  or isinstance(min, Array) and min.dtype not in _real_numeric_dtypes
289
256
  or isinstance(max, Array) and max.dtype not in _real_numeric_dtypes):
290
257
  raise TypeError("Only real numeric dtypes are allowed in clip")
291
- if not isinstance(min, (int, float, Array, type(None))):
292
- raise TypeError("min must be an None, int, float, or an array")
293
- if not isinstance(max, (int, float, Array, type(None))):
294
- raise TypeError("max must be an None, int, float, or an array")
295
-
296
- # Mixed dtype kinds is implementation defined
297
- if (x.dtype in _integer_dtypes
298
- and (isinstance(min, float) or
299
- isinstance(min, Array) and min.dtype in _real_floating_dtypes)):
300
- raise TypeError("min must be integral when x is integral")
301
- if (x.dtype in _integer_dtypes
302
- and (isinstance(max, float) or
303
- isinstance(max, Array) and max.dtype in _real_floating_dtypes)):
304
- raise TypeError("max must be integral when x is integral")
305
- if (x.dtype in _real_floating_dtypes
306
- and (isinstance(min, int) or
307
- isinstance(min, Array) and min.dtype in _integer_dtypes)):
308
- raise TypeError("min must be floating-point when x is floating-point")
309
- if (x.dtype in _real_floating_dtypes
310
- and (isinstance(max, int) or
311
- isinstance(max, Array) and max.dtype in _integer_dtypes)):
312
- raise TypeError("max must be floating-point when x is floating-point")
313
258
 
314
259
  if min is max is None:
315
- # Note: NumPy disallows min = max = None
316
260
  return x
317
261
 
262
+ for argname, arg in ("min", min), ("max", max):
263
+ if isinstance(arg, Array):
264
+ if x.device != arg.device:
265
+ raise ValueError(
266
+ f"Arrays from two different devices ({x.device} and {arg.device}) "
267
+ "can not be combined."
268
+ )
269
+ # Disallow subclasses of Python scalars, e.g. np.float64
270
+ elif type(arg) not in (int, float, NoneType):
271
+ raise TypeError(
272
+ f"{argname} must be None, int, float, or Array; got {type(arg)}"
273
+ )
274
+
275
+ # Mixed dtype kinds is implementation defined
276
+ if (x.dtype in _integer_dtypes
277
+ and (isinstance(arg, float) or
278
+ isinstance(arg, Array) and arg.dtype in _real_floating_dtypes)):
279
+ raise TypeError(f"{argname} must be integral when x is integral")
280
+ if (x.dtype in _real_floating_dtypes
281
+ and (isinstance(arg, int) or
282
+ isinstance(arg, Array) and arg.dtype in _integer_dtypes)):
283
+ raise TypeError(f"{arg} must be floating-point when x is floating-point")
284
+
318
285
  # Normalize to make the below logic simpler
319
286
  if min is not None:
320
287
  min = asarray(min)._array
@@ -351,6 +318,7 @@ def clip(
351
318
 
352
319
  def _isscalar(a):
353
320
  return isinstance(a, (int, float, type(None)))
321
+
354
322
  min_shape = () if _isscalar(min) else min.shape
355
323
  max_shape = () if _isscalar(max) else max.shape
356
324
 
@@ -372,329 +340,17 @@ def clip(
372
340
  return Array._new(out, device=device)
373
341
 
374
342
 
375
- def conj(x: Array, /) -> Array:
376
- """
377
- Array API compatible wrapper for :py:func:`np.conj <numpy.conj>`.
378
-
379
- See its docstring for more information.
380
- """
381
- if x.dtype not in _numeric_dtypes:
382
- raise TypeError("Only numeric dtypes are allowed in conj")
383
- return Array._new(np.conj(x._array), device=x.device)
384
-
385
-
386
- def cos(x: Array, /) -> Array:
387
- """
388
- Array API compatible wrapper for :py:func:`np.cos <numpy.cos>`.
389
-
390
- See its docstring for more information.
391
- """
392
- if x.dtype not in _floating_dtypes:
393
- raise TypeError("Only floating-point dtypes are allowed in cos")
394
- return Array._new(np.cos(x._array), device=x.device)
395
-
396
-
397
- def cosh(x: Array, /) -> Array:
398
- """
399
- Array API compatible wrapper for :py:func:`np.cosh <numpy.cosh>`.
400
-
401
- See its docstring for more information.
402
- """
403
- if x.dtype not in _floating_dtypes:
404
- raise TypeError("Only floating-point dtypes are allowed in cosh")
405
- return Array._new(np.cosh(x._array), device=x.device)
406
-
407
-
408
- def exp(x: Array, /) -> Array:
409
- """
410
- Array API compatible wrapper for :py:func:`np.exp <numpy.exp>`.
411
-
412
- See its docstring for more information.
413
- """
414
- if x.dtype not in _floating_dtypes:
415
- raise TypeError("Only floating-point dtypes are allowed in exp")
416
- return Array._new(np.exp(x._array), device=x.device)
417
-
418
-
419
- def expm1(x: Array, /) -> Array:
420
- """
421
- Array API compatible wrapper for :py:func:`np.expm1 <numpy.expm1>`.
422
-
423
- See its docstring for more information.
424
- """
425
- if x.dtype not in _floating_dtypes:
426
- raise TypeError("Only floating-point dtypes are allowed in expm1")
427
- return Array._new(np.expm1(x._array), device=x.device)
428
-
429
-
430
- def floor(x: Array, /) -> Array:
431
- """
432
- Array API compatible wrapper for :py:func:`np.floor <numpy.floor>`.
433
-
434
- See its docstring for more information.
435
- """
436
- if x.dtype not in _real_numeric_dtypes:
437
- raise TypeError("Only real numeric dtypes are allowed in floor")
438
- if x.dtype in _integer_dtypes:
439
- # Note: The return dtype of floor is the same as the input
440
- return x
441
- return Array._new(np.floor(x._array), device=x.device)
442
-
443
-
444
- def imag(x: Array, /) -> Array:
445
- """
446
- Array API compatible wrapper for :py:func:`np.imag <numpy.imag>`.
447
-
448
- See its docstring for more information.
449
- """
450
- if x.dtype not in _complex_floating_dtypes:
451
- raise TypeError("Only complex floating-point dtypes are allowed in imag")
452
- return Array._new(np.imag(x._array), device=x.device)
453
-
454
-
455
- def isfinite(x: Array, /) -> Array:
456
- """
457
- Array API compatible wrapper for :py:func:`np.isfinite <numpy.isfinite>`.
458
-
459
- See its docstring for more information.
460
- """
461
- if x.dtype not in _numeric_dtypes:
462
- raise TypeError("Only numeric dtypes are allowed in isfinite")
463
- return Array._new(np.isfinite(x._array), device=x.device)
464
-
465
-
466
- def isinf(x: Array, /) -> Array:
467
- """
468
- Array API compatible wrapper for :py:func:`np.isinf <numpy.isinf>`.
469
-
470
- See its docstring for more information.
471
- """
472
- if x.dtype not in _numeric_dtypes:
473
- raise TypeError("Only numeric dtypes are allowed in isinf")
474
- return Array._new(np.isinf(x._array), device=x.device)
475
-
476
-
477
- def isnan(x: Array, /) -> Array:
478
- """
479
- Array API compatible wrapper for :py:func:`np.isnan <numpy.isnan>`.
480
-
481
- See its docstring for more information.
482
- """
483
- if x.dtype not in _numeric_dtypes:
484
- raise TypeError("Only numeric dtypes are allowed in isnan")
485
- return Array._new(np.isnan(x._array), device=x.device)
486
-
487
-
488
- def log(x: Array, /) -> Array:
489
- """
490
- Array API compatible wrapper for :py:func:`np.log <numpy.log>`.
491
-
492
- See its docstring for more information.
493
- """
494
- if x.dtype not in _floating_dtypes:
495
- raise TypeError("Only floating-point dtypes are allowed in log")
496
- return Array._new(np.log(x._array), device=x.device)
497
-
498
-
499
- def log1p(x: Array, /) -> Array:
500
- """
501
- Array API compatible wrapper for :py:func:`np.log1p <numpy.log1p>`.
502
-
503
- See its docstring for more information.
504
- """
505
- if x.dtype not in _floating_dtypes:
506
- raise TypeError("Only floating-point dtypes are allowed in log1p")
507
- return Array._new(np.log1p(x._array), device=x.device)
508
-
509
-
510
- def log2(x: Array, /) -> Array:
511
- """
512
- Array API compatible wrapper for :py:func:`np.log2 <numpy.log2>`.
513
-
514
- See its docstring for more information.
515
- """
516
- if x.dtype not in _floating_dtypes:
517
- raise TypeError("Only floating-point dtypes are allowed in log2")
518
- return Array._new(np.log2(x._array), device=x.device)
519
-
520
-
521
- def log10(x: Array, /) -> Array:
522
- """
523
- Array API compatible wrapper for :py:func:`np.log10 <numpy.log10>`.
524
-
525
- See its docstring for more information.
526
- """
527
- if x.dtype not in _floating_dtypes:
528
- raise TypeError("Only floating-point dtypes are allowed in log10")
529
- return Array._new(np.log10(x._array), device=x.device)
530
-
531
-
532
- def logical_not(x: Array, /) -> Array:
533
- """
534
- Array API compatible wrapper for :py:func:`np.logical_not <numpy.logical_not>`.
535
-
536
- See its docstring for more information.
537
- """
538
- if x.dtype not in _boolean_dtypes:
539
- raise TypeError("Only boolean dtypes are allowed in logical_not")
540
- return Array._new(np.logical_not(x._array), device=x.device)
541
-
542
-
543
- def negative(x: Array, /) -> Array:
544
- """
545
- Array API compatible wrapper for :py:func:`np.negative <numpy.negative>`.
546
-
547
- See its docstring for more information.
548
- """
549
- if x.dtype not in _numeric_dtypes:
550
- raise TypeError("Only numeric dtypes are allowed in negative")
551
- return Array._new(np.negative(x._array), device=x.device)
552
-
553
-
554
- def positive(x: Array, /) -> Array:
555
- """
556
- Array API compatible wrapper for :py:func:`np.positive <numpy.positive>`.
557
-
558
- See its docstring for more information.
559
- """
560
- if x.dtype not in _numeric_dtypes:
561
- raise TypeError("Only numeric dtypes are allowed in positive")
562
- return Array._new(np.positive(x._array), device=x.device)
563
-
564
-
565
- def real(x: Array, /) -> Array:
566
- """
567
- Array API compatible wrapper for :py:func:`np.real <numpy.real>`.
568
-
569
- See its docstring for more information.
570
- """
571
- if x.dtype not in _numeric_dtypes:
572
- raise TypeError("Only numeric dtypes are allowed in real")
573
- return Array._new(np.real(x._array), device=x.device)
574
-
575
-
576
- @requires_api_version('2024.12')
577
- def reciprocal(x: Array, /) -> Array:
578
- """
579
- Array API compatible wrapper for :py:func:`np.reciprocal <numpy.reciprocal>`.
580
-
581
- See its docstring for more information.
582
- """
583
- if x.dtype not in _floating_dtypes:
584
- raise TypeError("Only floating-point dtypes are allowed in reciprocal")
585
- return Array._new(np.reciprocal(x._array), device=x.device)
586
-
587
- def round(x: Array, /) -> Array:
588
- """
589
- Array API compatible wrapper for :py:func:`np.round <numpy.round>`.
590
-
591
- See its docstring for more information.
592
- """
593
- if x.dtype not in _numeric_dtypes:
594
- raise TypeError("Only numeric dtypes are allowed in round")
595
- return Array._new(np.round(x._array), device=x.device)
596
-
597
-
598
343
  def sign(x: Array, /) -> Array:
599
344
  """
600
345
  Array API compatible wrapper for :py:func:`np.sign <numpy.sign>`.
601
346
 
602
347
  See its docstring for more information.
603
348
  """
349
+ if not isinstance(x, Array):
350
+ raise TypeError(f"Only Array objects are allowed; got {type(x)}")
604
351
  if x.dtype not in _numeric_dtypes:
605
352
  raise TypeError("Only numeric dtypes are allowed in sign")
353
+ # Special treatment to work around non-compliant NumPy 1.x behaviour
606
354
  if x.dtype in _complex_floating_dtypes:
607
355
  return x/abs(x)
608
356
  return Array._new(np.sign(x._array), device=x.device)
609
-
610
-
611
- @requires_api_version('2023.12')
612
- def signbit(x: Array, /) -> Array:
613
- """
614
- Array API compatible wrapper for :py:func:`np.signbit <numpy.signbit>`.
615
-
616
- See its docstring for more information.
617
- """
618
- if x.dtype not in _real_floating_dtypes:
619
- raise TypeError("Only real floating-point dtypes are allowed in signbit")
620
- return Array._new(np.signbit(x._array), device=x.device)
621
-
622
-
623
- def sin(x: Array, /) -> Array:
624
- """
625
- Array API compatible wrapper for :py:func:`np.sin <numpy.sin>`.
626
-
627
- See its docstring for more information.
628
- """
629
- if x.dtype not in _floating_dtypes:
630
- raise TypeError("Only floating-point dtypes are allowed in sin")
631
- return Array._new(np.sin(x._array), device=x.device)
632
-
633
-
634
- def sinh(x: Array, /) -> Array:
635
- """
636
- Array API compatible wrapper for :py:func:`np.sinh <numpy.sinh>`.
637
-
638
- See its docstring for more information.
639
- """
640
- if x.dtype not in _floating_dtypes:
641
- raise TypeError("Only floating-point dtypes are allowed in sinh")
642
- return Array._new(np.sinh(x._array), device=x.device)
643
-
644
-
645
- def square(x: Array, /) -> Array:
646
- """
647
- Array API compatible wrapper for :py:func:`np.square <numpy.square>`.
648
-
649
- See its docstring for more information.
650
- """
651
- if x.dtype not in _numeric_dtypes:
652
- raise TypeError("Only numeric dtypes are allowed in square")
653
- return Array._new(np.square(x._array), device=x.device)
654
-
655
-
656
- def sqrt(x: Array, /) -> Array:
657
- """
658
- Array API compatible wrapper for :py:func:`np.sqrt <numpy.sqrt>`.
659
-
660
- See its docstring for more information.
661
- """
662
- if x.dtype not in _floating_dtypes:
663
- raise TypeError("Only floating-point dtypes are allowed in sqrt")
664
- return Array._new(np.sqrt(x._array), device=x.device)
665
-
666
-
667
- def tan(x: Array, /) -> Array:
668
- """
669
- Array API compatible wrapper for :py:func:`np.tan <numpy.tan>`.
670
-
671
- See its docstring for more information.
672
- """
673
- if x.dtype not in _floating_dtypes:
674
- raise TypeError("Only floating-point dtypes are allowed in tan")
675
- return Array._new(np.tan(x._array), device=x.device)
676
-
677
-
678
- def tanh(x: Array, /) -> Array:
679
- """
680
- Array API compatible wrapper for :py:func:`np.tanh <numpy.tanh>`.
681
-
682
- See its docstring for more information.
683
- """
684
- if x.dtype not in _floating_dtypes:
685
- raise TypeError("Only floating-point dtypes are allowed in tanh")
686
- return Array._new(np.tanh(x._array), device=x.device)
687
-
688
-
689
- def trunc(x: Array, /) -> Array:
690
- """
691
- Array API compatible wrapper for :py:func:`np.trunc <numpy.trunc>`.
692
-
693
- See its docstring for more information.
694
- """
695
- if x.dtype not in _real_numeric_dtypes:
696
- raise TypeError("Only real numeric dtypes are allowed in trunc")
697
- if x.dtype in _integer_dtypes:
698
- # Note: The return dtype of trunc is the same as the input
699
- return x
700
- return Array._new(np.trunc(x._array), device=x.device)