pyopencl 2025.2.1__cp310-cp310-macosx_11_0_arm64.whl → 2025.2.2__cp310-cp310-macosx_11_0_arm64.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.

Potentially problematic release.


This version of pyopencl might be problematic. Click here for more details.

pyopencl/array.py CHANGED
@@ -34,14 +34,22 @@ import builtins
34
34
  from dataclasses import dataclass
35
35
  from functools import reduce
36
36
  from numbers import Number
37
- from typing import Any
37
+ from typing import (
38
+ TYPE_CHECKING,
39
+ Any,
40
+ ClassVar,
41
+ Concatenate,
42
+ Literal,
43
+ ParamSpec,
44
+ cast,
45
+ )
38
46
  from warnings import warn
39
47
 
40
48
  import numpy as np
49
+ from typing_extensions import Self, override
41
50
 
42
51
  import pyopencl as cl
43
52
  import pyopencl.elementwise as elementwise
44
- import pyopencl.tools as cl_tools
45
53
  from pyopencl import cltypes
46
54
  from pyopencl.characterize import has_double_support
47
55
  from pyopencl.compyte.array import (
@@ -53,6 +61,14 @@ from pyopencl.compyte.array import (
53
61
  )
54
62
 
55
63
 
64
+ if TYPE_CHECKING:
65
+ from collections.abc import Callable, Hashable
66
+
67
+ from numpy.typing import DTypeLike, NDArray
68
+
69
+ from pyopencl.typing import Allocator
70
+
71
+
56
72
  SCALAR_CLASSES = (Number, np.bool_, bool)
57
73
 
58
74
  if cl.get_cl_header_version() >= (2, 0):
@@ -61,6 +77,10 @@ else:
61
77
  _SVMPointer_or_nothing = ()
62
78
 
63
79
 
80
+ class _NoValue:
81
+ pass
82
+
83
+
64
84
  # {{{ _get_common_dtype
65
85
 
66
86
  class DoubleDowncastWarning(UserWarning):
@@ -163,7 +183,11 @@ vec = VecLookupWarner()
163
183
 
164
184
  # {{{ helper functionality
165
185
 
166
- def _splay(device, n, kernel_specific_max_wg_size=None):
186
+ def _splay(
187
+ device: cl.Device,
188
+ n: int,
189
+ kernel_specific_max_wg_size: int | None = None,
190
+ ):
167
191
  max_work_items = builtins.min(128, device.max_work_group_size)
168
192
 
169
193
  if kernel_specific_max_wg_size is not None:
@@ -198,7 +222,12 @@ def _splay(device, n, kernel_specific_max_wg_size=None):
198
222
  ARRAY_KERNEL_EXEC_HOOK = None
199
223
 
200
224
 
201
- def elwise_kernel_runner(kernel_getter):
225
+ P = ParamSpec("P")
226
+
227
+
228
+ def elwise_kernel_runner(
229
+ kernel_getter: Callable[Concatenate[Array, P], cl.Kernel]
230
+ ) -> Callable[Concatenate[Array, P], cl.Event]:
202
231
  """Take a kernel getter of the same signature as the kernel
203
232
  and return a function that invokes that kernel.
204
233
 
@@ -207,40 +236,31 @@ def elwise_kernel_runner(kernel_getter):
207
236
  from functools import wraps
208
237
 
209
238
  @wraps(kernel_getter)
210
- def kernel_runner(out, *args, **kwargs):
239
+ def kernel_runner(out: Array, *args: P.args, **kwargs: P.kwargs) -> cl.Event:
211
240
  assert isinstance(out, Array)
212
241
 
213
- wait_for = kwargs.pop("wait_for", None)
214
- queue = kwargs.pop("queue", None)
242
+ wait_for = cast("cl.WaitList", kwargs.pop("wait_for", None))
243
+ queue = cast("cl.CommandQueue | None", kwargs.pop("queue", None))
215
244
  if queue is None:
216
245
  queue = out.queue
217
246
 
218
247
  assert queue is not None
219
248
 
220
249
  knl = kernel_getter(out, *args, **kwargs)
221
- work_group_info = knl.get_work_group_info(
250
+ work_group_info = cast("int", knl.get_work_group_info(
222
251
  cl.kernel_work_group_info.WORK_GROUP_SIZE,
223
- queue.device)
252
+ queue.device))
224
253
  gs, ls = out._get_sizes(queue, work_group_info)
225
254
 
226
- args = (out, *args, out.size)
255
+ knl_args = (out, *args, out.size)
227
256
  if ARRAY_KERNEL_EXEC_HOOK is not None:
228
257
  return ARRAY_KERNEL_EXEC_HOOK( # pylint: disable=not-callable
229
- knl, queue, gs, ls, *args, wait_for=wait_for)
258
+ knl, queue, gs, ls, *knl_args, wait_for=wait_for)
230
259
  else:
231
- return knl(queue, gs, ls, *args, wait_for=wait_for)
260
+ return knl(queue, gs, ls, *knl_args, wait_for=wait_for)
232
261
 
233
262
  return kernel_runner
234
263
 
235
-
236
- class DefaultAllocator(cl_tools.DeferredAllocator):
237
- def __init__(self, *args, **kwargs):
238
- warn("pyopencl.array.DefaultAllocator is deprecated. "
239
- "It will be continue to exist throughout the 2013.x "
240
- "versions of PyOpenCL.",
241
- DeprecationWarning, stacklevel=2)
242
- cl_tools.DeferredAllocator.__init__(self, *args, **kwargs)
243
-
244
264
  # }}}
245
265
 
246
266
 
@@ -265,7 +285,8 @@ class _copy_queue: # noqa: N801
265
285
  pass
266
286
 
267
287
 
268
- _ARRAY_GET_SIZES_CACHE: dict[tuple[int, int, int], tuple[int, int]] = {}
288
+ _ARRAY_GET_SIZES_CACHE: \
289
+ dict[Hashable, tuple[tuple[int, ...], tuple[int, ...]]] = {}
269
290
  _BOOL_DTYPE = np.dtype(np.int8)
270
291
  _NOT_PRESENT = object()
271
292
 
@@ -456,15 +477,25 @@ class Array:
456
477
  .. automethod:: finish
457
478
  """
458
479
 
459
- __array_priority__ = 100
480
+ __array_priority__: ClassVar[int] = 100
481
+
482
+ queue: cl.CommandQueue | None
483
+ shape: tuple[int, ...]
484
+ dtype: np.dtype[Any]
485
+ strides: tuple[int, ...]
486
+ events: list[cl.Event]
487
+ nbytes: int
488
+ size: int
489
+ allocator: Allocator | None
490
+ base_data: cl.MemoryObjectHolder | cl.SVMPointer | None
460
491
 
461
492
  def __init__(
462
493
  self,
463
494
  cq: cl.Context | cl.CommandQueue | None,
464
495
  shape: tuple[int, ...] | int,
465
- dtype: Any,
496
+ dtype: DTypeLike,
466
497
  order: str = "C",
467
- allocator: cl_tools.AllocatorBase | None = None,
498
+ allocator: Allocator | None = None,
468
499
  data: Any = None,
469
500
  offset: int = 0,
470
501
  strides: tuple[int, ...] | None = None,
@@ -478,7 +509,7 @@ class Array:
478
509
  _queue: cl.CommandQueue | None = None) -> None:
479
510
  if _fast:
480
511
  # Assumptions, should be disabled if not testing
481
- if 0:
512
+ if TYPE_CHECKING:
482
513
  assert cq is None
483
514
  assert isinstance(_context, cl.Context)
484
515
  assert _queue is None or isinstance(_queue, cl.CommandQueue)
@@ -651,8 +682,15 @@ class Array:
651
682
  self._flags = f = _ArrayFlags(self)
652
683
  return f
653
684
 
654
- def _new_with_changes(self, data, offset, shape=None, dtype=None,
655
- strides=None, queue=_copy_queue, allocator=None):
685
+ def _new_with_changes(self,
686
+ data: cl.MemoryObjectHolder | cl.SVMPointer | None,
687
+ offset: int | None,
688
+ shape: tuple[int, ...] | None = None,
689
+ dtype: np.dtype[Any] | None = None,
690
+ strides: tuple[int, ...] | None = None,
691
+ queue: cl.CommandQueue | type[_copy_queue] | None = _copy_queue,
692
+ allocator: Allocator | None = None,
693
+ ) -> Self:
656
694
  """
657
695
  :arg data: *None* means allocate a new array.
658
696
  """
@@ -672,6 +710,8 @@ class Array:
672
710
  queue = self.queue
673
711
  if allocator is None:
674
712
  allocator = self.allocator
713
+ if offset is None:
714
+ offset = self.offset
675
715
 
676
716
  # If we're allocating new data, then there's not likely to be
677
717
  # a data dependency. Otherwise, the two arrays should probably
@@ -687,7 +727,7 @@ class Array:
687
727
  events=events,
688
728
  _fast=fast, _context=self.context, _queue=queue, _size=size)
689
729
 
690
- def with_queue(self, queue):
730
+ def with_queue(self, queue: cl.CommandQueue | None):
691
731
  """Return a copy of *self* with the default queue set to *queue*.
692
732
 
693
733
  *None* is allowed as a value for *queue*.
@@ -701,7 +741,10 @@ class Array:
701
741
  return self._new_with_changes(self.base_data, self.offset,
702
742
  queue=queue)
703
743
 
704
- def _get_sizes(self, queue, kernel_specific_max_wg_size=None):
744
+ def _get_sizes(self,
745
+ queue: cl.CommandQueue,
746
+ kernel_specific_max_wg_size: int | None = None
747
+ ) -> tuple[tuple[int, ...], tuple[int, ...]]:
705
748
  if not self.flags.forc:
706
749
  raise NotImplementedError("cannot operate on non-contiguous array")
707
750
  cache_key = (queue.device.int_ptr, self.size, kernel_specific_max_wg_size)
@@ -713,7 +756,11 @@ class Array:
713
756
  _ARRAY_GET_SIZES_CACHE[cache_key] = sizes
714
757
  return sizes
715
758
 
716
- def set(self, ary, queue=None, async_=None, **kwargs):
759
+ def set(self,
760
+ ary: NDArray[Any],
761
+ queue: cl.CommandQueue | None = None,
762
+ async_: bool = False,
763
+ ):
717
764
  """Transfer the contents the :class:`numpy.ndarray` object *ary*
718
765
  onto the device.
719
766
 
@@ -723,32 +770,8 @@ class Array:
723
770
  *async_* is a Boolean indicating whether the function is allowed
724
771
  to return before the transfer completes. To avoid synchronization
725
772
  bugs, this defaults to *False*.
726
-
727
- .. versionchanged:: 2017.2.1
728
-
729
- Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
730
- we will continue to accept *async* as a parameter, however this
731
- should be considered deprecated. *async_* is the new, official
732
- spelling.
733
773
  """
734
774
 
735
- # {{{ handle 'async' deprecation
736
-
737
- async_arg = kwargs.pop("async", None)
738
- if async_arg is not None:
739
- if async_ is not None:
740
- raise TypeError("may not specify both 'async' and 'async_'")
741
- async_ = async_arg
742
-
743
- if async_ is None:
744
- async_ = False
745
-
746
- if kwargs:
747
- raise TypeError("extra keyword arguments specified: %s"
748
- % ", ".join(kwargs))
749
-
750
- # }}}
751
-
752
775
  assert ary.size == self.size
753
776
  assert ary.dtype == self.dtype
754
777
 
@@ -756,36 +779,23 @@ class Array:
756
779
  raise RuntimeError("cannot set from non-contiguous array")
757
780
 
758
781
  if not _equal_strides(ary.strides, self.strides, self.shape):
759
- warn("Setting array from one with different "
760
- "strides/storage order. This will cease to work "
761
- "in 2013.x.",
762
- stacklevel=2)
782
+ raise RuntimeError("Setting array from one with different "
783
+ "strides/storage order.")
763
784
 
764
785
  if self.size:
786
+ queue = queue or self.queue
787
+ assert queue is not None
765
788
  event1 = cl.enqueue_copy(queue or self.queue, self.base_data, ary,
766
789
  dst_offset=self.offset,
767
790
  is_blocking=not async_)
768
791
 
769
792
  self.add_event(event1)
770
793
 
771
- def _get(self, queue=None, ary=None, async_=None, **kwargs):
772
- # {{{ handle 'async' deprecation
773
-
774
- async_arg = kwargs.pop("async", None)
775
- if async_arg is not None:
776
- if async_ is not None:
777
- raise TypeError("may not specify both 'async' and 'async_'")
778
- async_ = async_arg
779
-
780
- if async_ is None:
781
- async_ = False
782
-
783
- if kwargs:
784
- raise TypeError("extra keyword arguments specified: %s"
785
- % ", ".join(kwargs))
786
-
787
- # }}}
788
-
794
+ def _get(self,
795
+ queue: cl.CommandQueue | None = None,
796
+ ary: NDArray[Any] | None = None,
797
+ async_: bool = False,
798
+ ):
789
799
  if ary is None:
790
800
  ary = np.empty(self.shape, self.dtype)
791
801
 
@@ -812,52 +822,36 @@ class Array:
812
822
  "to associate one.")
813
823
 
814
824
  if self.size:
815
- event1 = cl.enqueue_copy(queue, ary, self.base_data,
825
+ assert self.base_data is not None
826
+ event1 = cast("cl.Event", cl.enqueue_copy(queue, ary, self.base_data,
816
827
  src_offset=self.offset,
817
- wait_for=self.events, is_blocking=not async_)
828
+ wait_for=self.events, is_blocking=not async_))
818
829
 
819
830
  self.add_event(event1)
820
831
  else:
821
- event1 = None
832
+ event1 = cl.enqueue_marker(queue, wait_for=self.events)
833
+ if not async_:
834
+ event1.wait()
822
835
 
823
836
  return ary, event1
824
837
 
825
- def get(self, queue=None, ary=None, async_=None, **kwargs):
838
+ def get(self,
839
+ queue: cl.CommandQueue | None = None,
840
+ ary: NDArray[Any] | None = None,
841
+ ) -> NDArray[Any]:
826
842
  """Transfer the contents of *self* into *ary* or a newly allocated
827
843
  :class:`numpy.ndarray`. If *ary* is given, it must have the same
828
844
  shape and dtype.
829
-
830
- .. versionchanged:: 2019.1.2
831
-
832
- Calling with ``async_=True`` was deprecated and replaced by
833
- :meth:`get_async`.
834
- The event returned by :meth:`pyopencl.enqueue_copy` is now stored into
835
- :attr:`events` to ensure data is not modified before the copy is
836
- complete.
837
-
838
- .. versionchanged:: 2015.2
839
-
840
- *ary* with different shape was deprecated.
841
-
842
- .. versionchanged:: 2017.2.1
843
-
844
- Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
845
- we will continue to accept *async* as a parameter, however this
846
- should be considered deprecated. *async_* is the new, official
847
- spelling.
848
845
  """
849
846
 
850
- if async_:
851
- warn("calling pyopencl.Array.get with 'async_=True' is deprecated. "
852
- "Please use pyopencl.Array.get_async for asynchronous "
853
- "device-to-host transfers",
854
- DeprecationWarning, stacklevel=2)
855
-
856
- ary, _event1 = self._get(queue=queue, ary=ary, async_=async_, **kwargs)
847
+ ary, _event1 = self._get(queue=queue, ary=ary)
857
848
 
858
849
  return ary
859
850
 
860
- def get_async(self, queue=None, ary=None, **kwargs):
851
+ def get_async(self,
852
+ queue: cl.CommandQueue | None = None,
853
+ ary: NDArray[Any] | None = None,
854
+ ) -> tuple[NDArray[Any], cl.Event]:
861
855
  """
862
856
  Asynchronous version of :meth:`get` which returns a tuple ``(ary, event)``
863
857
  containing the host array ``ary``
@@ -867,9 +861,9 @@ class Array:
867
861
  .. versionadded:: 2019.1.2
868
862
  """
869
863
 
870
- return self._get(queue=queue, ary=ary, async_=True, **kwargs)
864
+ return self._get(queue=queue, ary=ary, async_=True)
871
865
 
872
- def copy(self, queue=_copy_queue):
866
+ def copy(self, queue: cl.CommandQueue | type[_copy_queue] | None = _copy_queue):
873
867
  """
874
868
  :arg queue: The :class:`~pyopencl.CommandQueue` for the returned array.
875
869
 
@@ -881,20 +875,24 @@ class Array:
881
875
  """
882
876
 
883
877
  if queue is _copy_queue:
884
- queue = self.queue
878
+ queue_san = self.queue
879
+ else:
880
+ queue_san = cast("cl.CommandQueue | None", queue)
885
881
 
886
- result = self._new_like_me(queue=queue)
882
+ result = self._new_like_me(queue=queue_san)
887
883
 
888
884
  # result.queue won't be the same as queue if queue is None.
889
885
  # We force them to be the same here.
890
886
  if result.queue is not queue:
891
- result = result.with_queue(queue)
887
+ result = result.with_queue(queue_san)
892
888
 
893
889
  if not self.flags.forc:
894
890
  raise RuntimeError("cannot copy non-contiguous array")
895
891
 
896
892
  if self.nbytes:
897
- event1 = cl.enqueue_copy(queue or self.queue,
893
+ queue_san = queue_san or self.queue
894
+ assert queue_san is not None
895
+ event1 = cl.enqueue_copy(queue_san,
898
896
  result.base_data, self.base_data,
899
897
  src_offset=self.offset, byte_count=self.nbytes,
900
898
  wait_for=self.events)
@@ -935,7 +933,7 @@ class Array:
935
933
 
936
934
  @staticmethod
937
935
  @elwise_kernel_runner
938
- def _axpbyz(out, afac, a, bfac, b, queue=None):
936
+ def _axpbyz(out, afac, a, bfac, b, queue: cl.CommandQueue | None = None):
939
937
  """Compute ``out = selffac * self + otherfac*other``,
940
938
  where *other* is an array."""
941
939
  a_shape = a.shape
@@ -951,7 +949,7 @@ class Array:
951
949
 
952
950
  @staticmethod
953
951
  @elwise_kernel_runner
954
- def _axpbz(out, a, x, b, queue=None):
952
+ def _axpbz(out, a, x, b, queue: cl.CommandQueue | None = None):
955
953
  """Compute ``z = a * x + b``, where *b* is a scalar."""
956
954
  a = np.array(a)
957
955
  b = np.array(b)
@@ -961,7 +959,7 @@ class Array:
961
959
 
962
960
  @staticmethod
963
961
  @elwise_kernel_runner
964
- def _elwise_multiply(out, a, b, queue=None):
962
+ def _elwise_multiply(out, a, b, queue: cl.CommandQueue | None = None):
965
963
  a_shape = a.shape
966
964
  b_shape = b.shape
967
965
  out_shape = out.shape
@@ -976,7 +974,7 @@ class Array:
976
974
 
977
975
  @staticmethod
978
976
  @elwise_kernel_runner
979
- def _rdiv_scalar(out, ary, other, queue=None):
977
+ def _rdiv_scalar(out, ary, other, queue: cl.CommandQueue | None = None):
980
978
  other = np.array(other)
981
979
  assert out.shape == ary.shape
982
980
  return elementwise.get_rdivide_elwise_kernel(
@@ -984,7 +982,7 @@ class Array:
984
982
 
985
983
  @staticmethod
986
984
  @elwise_kernel_runner
987
- def _div(out, self, other, queue=None):
985
+ def _div(out, self, other, queue: cl.CommandQueue | None = None):
988
986
  """Divides an array by another array."""
989
987
  assert (self.shape == other.shape == out.shape
990
988
  or (self.shape == () and other.shape == out.shape)
@@ -1074,7 +1072,7 @@ class Array:
1074
1072
  return elementwise.get_copy_kernel(
1075
1073
  dest.context, dest.dtype, src.dtype)
1076
1074
 
1077
- def _new_like_me(self, dtype=None, queue=None):
1075
+ def _new_like_me(self, dtype=None, queue: cl.CommandQueue | None = None):
1078
1076
  if dtype is None:
1079
1077
  dtype = self.dtype
1080
1078
  strides = self.strides
@@ -1098,14 +1096,14 @@ class Array:
1098
1096
 
1099
1097
  @staticmethod
1100
1098
  @elwise_kernel_runner
1101
- def _scalar_binop(out, a, b, queue=None, op=None):
1099
+ def _scalar_binop(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1102
1100
  return elementwise.get_array_scalar_binop_kernel(
1103
1101
  out.context, op, out.dtype, a.dtype,
1104
1102
  np.array(b).dtype)
1105
1103
 
1106
1104
  @staticmethod
1107
1105
  @elwise_kernel_runner
1108
- def _array_binop(out, a, b, queue=None, op=None):
1106
+ def _array_binop(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1109
1107
  a_shape = a.shape
1110
1108
  b_shape = b.shape
1111
1109
  out_shape = out.shape
@@ -1119,7 +1117,7 @@ class Array:
1119
1117
 
1120
1118
  @staticmethod
1121
1119
  @elwise_kernel_runner
1122
- def _unop(out, a, queue=None, op=None):
1120
+ def _unop(out, a, queue: cl.CommandQueue | None = None, op=None):
1123
1121
  if out.shape != a.shape:
1124
1122
  raise ValueError("shapes of arguments do not match")
1125
1123
  return elementwise.get_unop_kernel(
@@ -1129,7 +1127,7 @@ class Array:
1129
1127
 
1130
1128
  # {{{ operators
1131
1129
 
1132
- def mul_add(self, selffac, other, otherfac, queue=None):
1130
+ def mul_add(self, selffac, other, otherfac, queue: cl.CommandQueue | None = None):
1133
1131
  """Return ``selffac * self + otherfac * other``.
1134
1132
  """
1135
1133
  queue = queue or self.queue
@@ -1152,7 +1150,7 @@ class Array:
1152
1150
  else:
1153
1151
  raise NotImplementedError
1154
1152
 
1155
- def __add__(self, other):
1153
+ def __add__(self, other) -> Self:
1156
1154
  """Add an array with an array or an array with a scalar."""
1157
1155
 
1158
1156
  if isinstance(other, Array):
@@ -1178,7 +1176,7 @@ class Array:
1178
1176
 
1179
1177
  __radd__ = __add__
1180
1178
 
1181
- def __sub__(self, other):
1179
+ def __sub__(self, other) -> Self:
1182
1180
  """Subtract an array from an array or a scalar from an array."""
1183
1181
 
1184
1182
  if isinstance(other, Array):
@@ -1201,7 +1199,7 @@ class Array:
1201
1199
  else:
1202
1200
  return NotImplemented
1203
1201
 
1204
- def __rsub__(self, other):
1202
+ def __rsub__(self, other) -> Self:
1205
1203
  """Subtracts an array by a scalar or an array::
1206
1204
 
1207
1205
  x = n - self
@@ -1217,7 +1215,7 @@ class Array:
1217
1215
  else:
1218
1216
  return NotImplemented
1219
1217
 
1220
- def __iadd__(self, other):
1218
+ def __iadd__(self, other) -> Self:
1221
1219
  if isinstance(other, Array):
1222
1220
  if other.shape != self.shape and other.shape != ():
1223
1221
  raise NotImplementedError("Broadcasting binary op with shapes:"
@@ -1235,7 +1233,7 @@ class Array:
1235
1233
  else:
1236
1234
  return NotImplemented
1237
1235
 
1238
- def __isub__(self, other):
1236
+ def __isub__(self, other) -> Self:
1239
1237
  if isinstance(other, Array):
1240
1238
  if other.shape != self.shape and other.shape != ():
1241
1239
  raise NotImplementedError("Broadcasting binary op with shapes:"
@@ -1250,15 +1248,15 @@ class Array:
1250
1248
  else:
1251
1249
  return NotImplemented
1252
1250
 
1253
- def __pos__(self):
1251
+ def __pos__(self) -> Self:
1254
1252
  return self
1255
1253
 
1256
- def __neg__(self):
1254
+ def __neg__(self) -> Self:
1257
1255
  result = self._new_like_me()
1258
1256
  result.add_event(self._axpbz(result, -1, self, 0))
1259
1257
  return result
1260
1258
 
1261
- def __mul__(self, other):
1259
+ def __mul__(self, other) -> Self:
1262
1260
  if isinstance(other, Array):
1263
1261
  result = _get_broadcasted_binary_op_result(self, other, self.queue)
1264
1262
  result.add_event(
@@ -1274,7 +1272,7 @@ class Array:
1274
1272
  else:
1275
1273
  return NotImplemented
1276
1274
 
1277
- def __rmul__(self, other):
1275
+ def __rmul__(self, other) -> Self:
1278
1276
  if np.isscalar(other):
1279
1277
  common_dtype = _get_common_dtype(self, other, self.queue)
1280
1278
  result = self._new_like_me(common_dtype)
@@ -1285,7 +1283,7 @@ class Array:
1285
1283
  else:
1286
1284
  return NotImplemented
1287
1285
 
1288
- def __imul__(self, other):
1286
+ def __imul__(self, other) -> Self:
1289
1287
  if isinstance(other, Array):
1290
1288
  if other.shape != self.shape and other.shape != ():
1291
1289
  raise NotImplementedError("Broadcasting binary op with shapes:"
@@ -1300,7 +1298,7 @@ class Array:
1300
1298
  else:
1301
1299
  return NotImplemented
1302
1300
 
1303
- def __div__(self, other):
1301
+ def __div__(self, other) -> Self:
1304
1302
  """Divides an array by an array or a scalar, i.e. ``self / other``.
1305
1303
  """
1306
1304
  if isinstance(other, Array):
@@ -1326,7 +1324,7 @@ class Array:
1326
1324
 
1327
1325
  __truediv__ = __div__
1328
1326
 
1329
- def __rdiv__(self, other):
1327
+ def __rdiv__(self, other) -> Self:
1330
1328
  """Divides an array by a scalar or an array, i.e. ``other / self``.
1331
1329
  """
1332
1330
  common_dtype = _get_truedivide_dtype(self, other, self.queue)
@@ -1345,7 +1343,7 @@ class Array:
1345
1343
 
1346
1344
  __rtruediv__ = __rdiv__
1347
1345
 
1348
- def __itruediv__(self, other):
1346
+ def __itruediv__(self, other) -> Self:
1349
1347
  # raise an error if the result cannot be cast to self
1350
1348
  common_dtype = _get_truedivide_dtype(self, other, self.queue)
1351
1349
  if not np.can_cast(common_dtype, self.dtype.type, "same_kind"):
@@ -1370,7 +1368,7 @@ class Array:
1370
1368
  else:
1371
1369
  return NotImplemented
1372
1370
 
1373
- def __and__(self, other):
1371
+ def __and__(self, other) -> Self:
1374
1372
  common_dtype = _get_common_dtype(self, other, self.queue)
1375
1373
 
1376
1374
  if not np.issubdtype(common_dtype, np.integer):
@@ -1390,7 +1388,7 @@ class Array:
1390
1388
 
1391
1389
  __rand__ = __and__ # commutes
1392
1390
 
1393
- def __or__(self, other):
1391
+ def __or__(self, other) -> Self:
1394
1392
  common_dtype = _get_common_dtype(self, other, self.queue)
1395
1393
 
1396
1394
  if not np.issubdtype(common_dtype, np.integer):
@@ -1411,7 +1409,7 @@ class Array:
1411
1409
 
1412
1410
  __ror__ = __or__ # commutes
1413
1411
 
1414
- def __xor__(self, other):
1412
+ def __xor__(self, other) -> Self:
1415
1413
  common_dtype = _get_common_dtype(self, other, self.queue)
1416
1414
 
1417
1415
  if not np.issubdtype(common_dtype, np.integer):
@@ -1431,7 +1429,7 @@ class Array:
1431
1429
 
1432
1430
  __rxor__ = __xor__ # commutes
1433
1431
 
1434
- def __iand__(self, other):
1432
+ def __iand__(self, other) -> Self:
1435
1433
  common_dtype = _get_common_dtype(self, other, self.queue)
1436
1434
 
1437
1435
  if not np.issubdtype(common_dtype, np.integer):
@@ -1450,7 +1448,7 @@ class Array:
1450
1448
  else:
1451
1449
  return NotImplemented
1452
1450
 
1453
- def __ior__(self, other):
1451
+ def __ior__(self, other) -> Self:
1454
1452
  common_dtype = _get_common_dtype(self, other, self.queue)
1455
1453
 
1456
1454
  if not np.issubdtype(common_dtype, np.integer):
@@ -1469,7 +1467,7 @@ class Array:
1469
1467
  else:
1470
1468
  return NotImplemented
1471
1469
 
1472
- def __ixor__(self, other):
1470
+ def __ixor__(self, other) -> Self:
1473
1471
  common_dtype = _get_common_dtype(self, other, self.queue)
1474
1472
 
1475
1473
  if not np.issubdtype(common_dtype, np.integer):
@@ -1488,7 +1486,9 @@ class Array:
1488
1486
  else:
1489
1487
  return NotImplemented
1490
1488
 
1491
- def _zero_fill(self, queue=None, wait_for=None):
1489
+ def _zero_fill(self,
1490
+ queue: cl.CommandQueue | None = None,
1491
+ wait_for: cl.WaitList = None) -> None:
1492
1492
  queue = queue or self.queue
1493
1493
 
1494
1494
  if not self.size:
@@ -1510,7 +1510,10 @@ class Array:
1510
1510
  zero = np.zeros((), self.dtype)
1511
1511
  self.fill(zero, queue=queue)
1512
1512
 
1513
- def fill(self, value, queue=None, wait_for=None):
1513
+ def fill(self,
1514
+ value: object,
1515
+ queue: cl.CommandQueue | None = None,
1516
+ wait_for: cl.WaitList = None) -> Self:
1514
1517
  """Fill the array with *scalar*.
1515
1518
 
1516
1519
  :returns: *self*.
@@ -1521,14 +1524,14 @@ class Array:
1521
1524
 
1522
1525
  return self
1523
1526
 
1524
- def __len__(self):
1527
+ def __len__(self) -> int:
1525
1528
  """Returns the size of the leading dimension of *self*."""
1526
1529
  if len(self.shape):
1527
1530
  return self.shape[0]
1528
1531
  else:
1529
1532
  return TypeError("len() of unsized object")
1530
1533
 
1531
- def __abs__(self):
1534
+ def __abs__(self) -> Self:
1532
1535
  """Return an ``Array`` of the absolute values of the elements
1533
1536
  of *self*.
1534
1537
  """
@@ -1537,7 +1540,7 @@ class Array:
1537
1540
  result.add_event(self._abs(result, self))
1538
1541
  return result
1539
1542
 
1540
- def __pow__(self, other):
1543
+ def __pow__(self, other) -> Self:
1541
1544
  """Exponentiation by a scalar or elementwise by another
1542
1545
  :class:`Array`.
1543
1546
  """
@@ -1558,7 +1561,7 @@ class Array:
1558
1561
  else:
1559
1562
  return NotImplemented
1560
1563
 
1561
- def __rpow__(self, other):
1564
+ def __rpow__(self, other) -> Self:
1562
1565
  if np.isscalar(other):
1563
1566
  common_dtype = _get_common_dtype(self, other, self.queue)
1564
1567
  result = self._new_like_me(common_dtype)
@@ -1579,7 +1582,7 @@ class Array:
1579
1582
 
1580
1583
  # }}}
1581
1584
 
1582
- def reverse(self, queue=None):
1585
+ def reverse(self, queue: cl.CommandQueue | None = None) -> Self:
1583
1586
  """Return this array in reversed order. The array is treated
1584
1587
  as one-dimensional.
1585
1588
  """
@@ -1588,7 +1591,7 @@ class Array:
1588
1591
  result.add_event(self._reverse(result, self))
1589
1592
  return result
1590
1593
 
1591
- def astype(self, dtype, queue=None):
1594
+ def astype(self, dtype, queue: cl.CommandQueue | None = None):
1592
1595
  """Return a copy of *self*, cast to *dtype*."""
1593
1596
  if dtype == self.dtype:
1594
1597
  return self.copy()
@@ -1599,48 +1602,55 @@ class Array:
1599
1602
 
1600
1603
  # {{{ rich comparisons, any, all
1601
1604
 
1602
- def __bool__(self):
1605
+ def __bool__(self) -> bool:
1603
1606
  if self.shape == ():
1604
1607
  return bool(self.get())
1605
1608
  else:
1606
1609
  raise ValueError("The truth value of an array with "
1607
1610
  "more than one element is ambiguous. Use a.any() or a.all()")
1608
1611
 
1609
- def any(self, queue=None, wait_for=None):
1612
+ def any(self,
1613
+ queue: cl.CommandQueue | None = None,
1614
+ wait_for: cl.WaitList = None
1615
+ ) -> Self:
1610
1616
  from pyopencl.reduction import get_any_kernel
1611
1617
  krnl = get_any_kernel(self.context, self.dtype)
1612
1618
  if wait_for is None:
1613
1619
  wait_for = []
1614
1620
  result, event1 = krnl(self, queue=queue,
1615
- wait_for=wait_for + self.events, return_event=True)
1621
+ wait_for=[*wait_for, *self.events], return_event=True)
1616
1622
  result.add_event(event1)
1617
1623
  return result
1618
1624
 
1619
- def all(self, queue=None, wait_for=None):
1625
+ def all(self,
1626
+ queue: cl.CommandQueue | None = None,
1627
+ wait_for: cl.WaitList = None
1628
+ ) -> Self:
1620
1629
  from pyopencl.reduction import get_all_kernel
1621
1630
  krnl = get_all_kernel(self.context, self.dtype)
1622
1631
  if wait_for is None:
1623
1632
  wait_for = []
1624
1633
  result, event1 = krnl(self, queue=queue,
1625
- wait_for=wait_for + self.events, return_event=True)
1634
+ wait_for=[*wait_for, *self.events], return_event=True)
1626
1635
  result.add_event(event1)
1627
1636
  return result
1628
1637
 
1629
1638
  @staticmethod
1630
1639
  @elwise_kernel_runner
1631
- def _scalar_comparison(out, a, b, queue=None, op=None):
1640
+ def _scalar_comparison(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1632
1641
  return elementwise.get_array_scalar_comparison_kernel(
1633
1642
  out.context, op, a.dtype)
1634
1643
 
1635
1644
  @staticmethod
1636
1645
  @elwise_kernel_runner
1637
- def _array_comparison(out, a, b, queue=None, op=None):
1646
+ def _array_comparison(out, a, b, queue: cl.CommandQueue | None = None, op=None):
1638
1647
  if a.shape != b.shape:
1639
1648
  raise ValueError("shapes of comparison arguments do not match")
1640
1649
  return elementwise.get_array_comparison_kernel(
1641
1650
  out.context, op, a.dtype, b.dtype)
1642
1651
 
1643
- def __eq__(self, other):
1652
+ @override
1653
+ def __eq__(self, other: object) -> Self: # pyright: ignore[reportIncompatibleMethodOverride]
1644
1654
  if isinstance(other, Array):
1645
1655
  result = self._new_like_me(_BOOL_DTYPE)
1646
1656
  result.add_event(
@@ -1654,7 +1664,8 @@ class Array:
1654
1664
  else:
1655
1665
  return NotImplemented
1656
1666
 
1657
- def __ne__(self, other):
1667
+ @override
1668
+ def __ne__(self, other: object) -> Self: # pyright: ignore[reportIncompatibleMethodOverride]
1658
1669
  if isinstance(other, Array):
1659
1670
  result = self._new_like_me(_BOOL_DTYPE)
1660
1671
  result.add_event(
@@ -1668,7 +1679,7 @@ class Array:
1668
1679
  else:
1669
1680
  return NotImplemented
1670
1681
 
1671
- def __le__(self, other):
1682
+ def __le__(self, other) -> Self:
1672
1683
  if isinstance(other, Array):
1673
1684
  result = self._new_like_me(_BOOL_DTYPE)
1674
1685
  result.add_event(
@@ -1681,7 +1692,7 @@ class Array:
1681
1692
  else:
1682
1693
  return NotImplemented
1683
1694
 
1684
- def __ge__(self, other):
1695
+ def __ge__(self, other) -> Self:
1685
1696
  if isinstance(other, Array):
1686
1697
  result = self._new_like_me(_BOOL_DTYPE)
1687
1698
  result.add_event(
@@ -1695,7 +1706,7 @@ class Array:
1695
1706
  else:
1696
1707
  return NotImplemented
1697
1708
 
1698
- def __lt__(self, other):
1709
+ def __lt__(self, other) -> Self:
1699
1710
  if isinstance(other, Array):
1700
1711
  result = self._new_like_me(_BOOL_DTYPE)
1701
1712
  result.add_event(
@@ -1709,7 +1720,7 @@ class Array:
1709
1720
  else:
1710
1721
  return NotImplemented
1711
1722
 
1712
- def __gt__(self, other):
1723
+ def __gt__(self, other) -> Self:
1713
1724
  if isinstance(other, Array):
1714
1725
  result = self._new_like_me(_BOOL_DTYPE)
1715
1726
  result.add_event(
@@ -1728,7 +1739,7 @@ class Array:
1728
1739
  # {{{ complex-valued business
1729
1740
 
1730
1741
  @property
1731
- def real(self):
1742
+ def real(self) -> Self:
1732
1743
  """
1733
1744
  .. versionadded:: 2012.1
1734
1745
  """
@@ -1741,7 +1752,7 @@ class Array:
1741
1752
  return self
1742
1753
 
1743
1754
  @property
1744
- def imag(self):
1755
+ def imag(self) -> Self:
1745
1756
  """
1746
1757
  .. versionadded:: 2012.1
1747
1758
  """
@@ -1753,7 +1764,7 @@ class Array:
1753
1764
  else:
1754
1765
  return zeros_like(self)
1755
1766
 
1756
- def conj(self):
1767
+ def conj(self) -> Self:
1757
1768
  """
1758
1769
  .. versionadded:: 2012.1
1759
1770
  """
@@ -1770,7 +1781,7 @@ class Array:
1770
1781
 
1771
1782
  # {{{ event management
1772
1783
 
1773
- def add_event(self, evt):
1784
+ def add_event(self, evt: cl.Event) -> None:
1774
1785
  """Add *evt* to :attr:`events`. If :attr:`events` is too long, this method
1775
1786
  may implicitly wait for a subset of :attr:`events` and clear them from the
1776
1787
  list.
@@ -1784,7 +1795,7 @@ class Array:
1784
1795
  cl.wait_for_events(wait_events)
1785
1796
  del self.events[:n_wait]
1786
1797
 
1787
- def finish(self):
1798
+ def finish(self) -> None:
1788
1799
  """Wait for the entire contents of :attr:`events`, clear it."""
1789
1800
 
1790
1801
  if self.events:
@@ -2022,7 +2033,11 @@ class Array:
2022
2033
 
2023
2034
  # }}}
2024
2035
 
2025
- def map_to_host(self, queue=None, flags=None, is_blocking=True, wait_for=None):
2036
+ def map_to_host(self,
2037
+ queue: cl.CommandQueue | None = None,
2038
+ flags=None,
2039
+ is_blocking: bool = True,
2040
+ wait_for: cl.WaitList = None):
2026
2041
  """If *is_blocking*, return a :class:`numpy.ndarray` corresponding to the
2027
2042
  same memory as *self*.
2028
2043
 
@@ -2046,7 +2061,7 @@ class Array:
2046
2061
  ary, evt = cl.enqueue_map_buffer(
2047
2062
  queue or self.queue, self.base_data, flags, self.offset,
2048
2063
  self.shape, self.dtype, strides=self.strides,
2049
- wait_for=wait_for + self.events, is_blocking=is_blocking)
2064
+ wait_for=[*wait_for, *self.events], is_blocking=is_blocking)
2050
2065
 
2051
2066
  if is_blocking:
2052
2067
  return ary
@@ -2153,7 +2168,12 @@ class Array:
2153
2168
  shape=tuple(new_shape),
2154
2169
  strides=tuple(new_strides))
2155
2170
 
2156
- def setitem(self, subscript, value, queue=None, wait_for=None):
2171
+ def setitem(self,
2172
+ subscript: Array | slice | int,
2173
+ value: object,
2174
+ queue: cl.CommandQueue | None = None,
2175
+ wait_for: cl.WaitList = None
2176
+ ):
2157
2177
  """Like :meth:`__setitem__`, but with the ability to specify
2158
2178
  a *queue* and *wait_for*.
2159
2179
 
@@ -2164,10 +2184,11 @@ class Array:
2164
2184
  Added *wait_for*.
2165
2185
  """
2166
2186
 
2167
- queue = queue or self.queue or value.queue
2187
+ queue = queue or self.queue
2188
+ assert queue is not None
2168
2189
  if wait_for is None:
2169
2190
  wait_for = []
2170
- wait_for = wait_for + self.events
2191
+ wait_for = [*wait_for, *self.events]
2171
2192
 
2172
2193
  if isinstance(subscript, Array):
2173
2194
  if subscript.dtype.kind not in ("i", "u"):
@@ -2193,6 +2214,7 @@ class Array:
2193
2214
 
2194
2215
  if isinstance(value, np.ndarray):
2195
2216
  if subarray.shape == value.shape and subarray.strides == value.strides:
2217
+ assert subarray.base_data is not None
2196
2218
  self.add_event(
2197
2219
  cl.enqueue_copy(queue, subarray.base_data,
2198
2220
  value, dst_offset=subarray.offset, wait_for=wait_for))
@@ -2262,8 +2284,13 @@ class _same_as_transfer: # noqa: N801
2262
2284
  pass
2263
2285
 
2264
2286
 
2265
- def to_device(queue, ary, allocator=None, async_=None,
2266
- array_queue=_same_as_transfer, **kwargs):
2287
+ def to_device(
2288
+ queue: cl.CommandQueue,
2289
+ ary: NDArray[Any],
2290
+ allocator: Allocator | None = None,
2291
+ async_: bool = False,
2292
+ array_queue=_same_as_transfer,
2293
+ ) -> Array:
2267
2294
  """Return a :class:`Array` that is an exact copy of the
2268
2295
  :class:`numpy.ndarray` instance *ary*.
2269
2296
 
@@ -2276,32 +2303,8 @@ def to_device(queue, ary, allocator=None, async_=None,
2276
2303
 
2277
2304
  .. versionchanged:: 2015.2
2278
2305
  *array_queue* argument was added.
2279
-
2280
- .. versionchanged:: 2017.2.1
2281
-
2282
- Python 3.7 makes ``async`` a reserved keyword. On older Pythons,
2283
- we will continue to accept *async* as a parameter, however this
2284
- should be considered deprecated. *async_* is the new, official
2285
- spelling.
2286
2306
  """
2287
2307
 
2288
- # {{{ handle 'async' deprecation
2289
-
2290
- async_arg = kwargs.pop("async", None)
2291
- if async_arg is not None:
2292
- if async_ is not None:
2293
- raise TypeError("may not specify both 'async' and 'async_'")
2294
- async_ = async_arg
2295
-
2296
- if async_ is None:
2297
- async_ = False
2298
-
2299
- if kwargs:
2300
- raise TypeError("extra keyword arguments specified: %s"
2301
- % ", ".join(kwargs))
2302
-
2303
- # }}}
2304
-
2305
2308
  if ary.dtype == object:
2306
2309
  raise RuntimeError("to_device does not work on object arrays.")
2307
2310
 
@@ -2319,7 +2322,13 @@ def to_device(queue, ary, allocator=None, async_=None,
2319
2322
  empty = Array
2320
2323
 
2321
2324
 
2322
- def zeros(queue, shape, dtype, order="C", allocator=None):
2325
+ def zeros(
2326
+ queue: cl.CommandQueue,
2327
+ shape: int | tuple[int, ...],
2328
+ dtype: DTypeLike,
2329
+ order: Literal["C"] | Literal["F"] = "C",
2330
+ allocator: Allocator | None = None,
2331
+ ) -> Array:
2323
2332
  """Same as :func:`empty`, but the :class:`Array` is zero-initialized before
2324
2333
  being returned.
2325
2334
 
@@ -2334,7 +2343,11 @@ def zeros(queue, shape, dtype, order="C", allocator=None):
2334
2343
  return result
2335
2344
 
2336
2345
 
2337
- def empty_like(ary, queue=_copy_queue, allocator=None):
2346
+ def empty_like(
2347
+ ary: Array,
2348
+ queue: cl.CommandQueue | type[_copy_queue] | None = _copy_queue,
2349
+ allocator: Allocator | None = None,
2350
+ ):
2338
2351
  """Make a new, uninitialized :class:`Array` having the same properties
2339
2352
  as *other_ary*.
2340
2353
  """
@@ -2466,7 +2479,13 @@ def _take(result, ary, indices):
2466
2479
  result.context, result.dtype, indices.dtype)
2467
2480
 
2468
2481
 
2469
- def take(a, indices, out=None, queue=None, wait_for=None):
2482
+ def take(
2483
+ a: Array,
2484
+ indices: Array,
2485
+ out: Array | None = None,
2486
+ queue: cl.CommandQueue | None = None,
2487
+ wait_for: cl.WaitList = None
2488
+ ) -> Array:
2470
2489
  """Return the :class:`Array` ``[a[indices[0]], ..., a[indices[n]]]``.
2471
2490
  For the moment, *a* must be a type that can be bound to a texture.
2472
2491
  """
@@ -2481,7 +2500,7 @@ def take(a, indices, out=None, queue=None, wait_for=None):
2481
2500
  return out
2482
2501
 
2483
2502
 
2484
- def multi_take(arrays, indices, out=None, queue=None):
2503
+ def multi_take(arrays, indices, out=None, queue: cl.CommandQueue | None = None):
2485
2504
  if not len(arrays):
2486
2505
  return []
2487
2506
 
@@ -2544,7 +2563,7 @@ def multi_take(arrays, indices, out=None, queue=None):
2544
2563
 
2545
2564
 
2546
2565
  def multi_take_put(arrays, dest_indices, src_indices, dest_shape=None,
2547
- out=None, queue=None, src_offsets=None):
2566
+ out=None, queue: cl.CommandQueue | None = None, src_offsets=None):
2548
2567
  if not len(arrays):
2549
2568
  return []
2550
2569
 
@@ -2626,8 +2645,14 @@ def multi_take_put(arrays, dest_indices, src_indices, dest_shape=None,
2626
2645
  return out
2627
2646
 
2628
2647
 
2629
- def multi_put(arrays, dest_indices, dest_shape=None, out=None, queue=None,
2630
- wait_for=None):
2648
+ def multi_put(
2649
+ arrays,
2650
+ dest_indices: Array,
2651
+ dest_shape=None,
2652
+ out=None,
2653
+ queue: cl.CommandQueue | None = None,
2654
+ wait_for: cl.WaitList = None
2655
+ ):
2631
2656
  if not len(arrays):
2632
2657
  return []
2633
2658
 
@@ -2636,9 +2661,10 @@ def multi_put(arrays, dest_indices, dest_shape=None, out=None, queue=None,
2636
2661
  a_allocator = arrays[0].allocator
2637
2662
  context = dest_indices.context
2638
2663
  queue = queue or dest_indices.queue
2664
+ assert queue is not None
2639
2665
  if wait_for is None:
2640
2666
  wait_for = []
2641
- wait_for = wait_for + dest_indices.events
2667
+ wait_for = [*wait_for, *dest_indices.events]
2642
2668
 
2643
2669
  vec_count = len(arrays)
2644
2670
 
@@ -2705,7 +2731,7 @@ def multi_put(arrays, dest_indices, dest_shape=None, out=None, queue=None,
2705
2731
  return out
2706
2732
 
2707
2733
 
2708
- def concatenate(arrays, axis=0, queue=None, allocator=None):
2734
+ def concatenate(arrays, axis=0, queue: cl.CommandQueue | None = None, allocator=None):
2709
2735
  """
2710
2736
  .. versionadded:: 2013.1
2711
2737
 
@@ -2777,7 +2803,7 @@ def _diff(result, array):
2777
2803
  return elementwise.get_diff_kernel(array.context, array.dtype)
2778
2804
 
2779
2805
 
2780
- def diff(array, queue=None, allocator=None):
2806
+ def diff(array, queue: cl.CommandQueue | None = None, allocator=None):
2781
2807
  """
2782
2808
  .. versionadded:: 2013.2
2783
2809
  """
@@ -2796,7 +2822,7 @@ def diff(array, queue=None, allocator=None):
2796
2822
  return result
2797
2823
 
2798
2824
 
2799
- def hstack(arrays, queue=None):
2825
+ def hstack(arrays, queue: cl.CommandQueue | None = None):
2800
2826
  if len(arrays) == 0:
2801
2827
  raise ValueError("need at least one array to hstack")
2802
2828
 
@@ -2831,7 +2857,7 @@ def hstack(arrays, queue=None):
2831
2857
  return result
2832
2858
 
2833
2859
 
2834
- def stack(arrays, axis=0, queue=None):
2860
+ def stack(arrays, axis=0, queue: cl.CommandQueue | None = None):
2835
2861
  """
2836
2862
  Join a sequence of arrays along a new axis.
2837
2863
 
@@ -2934,7 +2960,12 @@ def _if_positive(result, criterion, then_, else_):
2934
2960
  )
2935
2961
 
2936
2962
 
2937
- def if_positive(criterion, then_, else_, out=None, queue=None):
2963
+ def if_positive(
2964
+ criterion,
2965
+ then_,
2966
+ else_,
2967
+ out=None,
2968
+ queue: cl.CommandQueue | None = None):
2938
2969
  """Return an array like *then_*, which, for the element at index *i*,
2939
2970
  contains *then_[i]* if *criterion[i]>0*, else *else_[i]*.
2940
2971
  """
@@ -3018,7 +3049,7 @@ def _minimum_maximum_backend(out, a, b, minmax):
3018
3049
  elementwise.get_argument_kind(b))
3019
3050
 
3020
3051
 
3021
- def maximum(a, b, out=None, queue=None):
3052
+ def maximum(a, b, out=None, queue: cl.CommandQueue | None = None):
3022
3053
  """Return the elementwise maximum of *a* and *b*."""
3023
3054
 
3024
3055
  a_is_scalar = np.isscalar(a)
@@ -3045,7 +3076,7 @@ def maximum(a, b, out=None, queue=None):
3045
3076
  return out
3046
3077
 
3047
3078
 
3048
- def minimum(a, b, out=None, queue=None):
3079
+ def minimum(a, b, out=None, queue: cl.CommandQueue | None = None):
3049
3080
  """Return the elementwise minimum of *a* and *b*."""
3050
3081
  a_is_scalar = np.isscalar(a)
3051
3082
  b_is_scalar = np.isscalar(b)
@@ -3075,7 +3106,7 @@ def minimum(a, b, out=None, queue=None):
3075
3106
 
3076
3107
  # {{{ logical ops
3077
3108
 
3078
- def _logical_op(x1, x2, out, operator, queue=None):
3109
+ def _logical_op(x1, x2, out, operator, queue: cl.CommandQueue | None = None):
3079
3110
  # NOTE: Copied from pycuda.gpuarray
3080
3111
  assert operator in ["&&", "||"]
3081
3112
 
@@ -3135,21 +3166,21 @@ def _logical_op(x1, x2, out, operator, queue=None):
3135
3166
  return out
3136
3167
 
3137
3168
 
3138
- def logical_and(x1, x2, /, out=None, queue=None):
3169
+ def logical_and(x1, x2, /, out=None, queue: cl.CommandQueue | None = None):
3139
3170
  """
3140
3171
  Returns the element-wise logical AND of *x1* and *x2*.
3141
3172
  """
3142
3173
  return _logical_op(x1, x2, out, "&&", queue=queue)
3143
3174
 
3144
3175
 
3145
- def logical_or(x1, x2, /, out=None, queue=None):
3176
+ def logical_or(x1, x2, /, out=None, queue: cl.CommandQueue | None = None):
3146
3177
  """
3147
3178
  Returns the element-wise logical OR of *x1* and *x2*.
3148
3179
  """
3149
3180
  return _logical_op(x1, x2, out, "||", queue=queue)
3150
3181
 
3151
3182
 
3152
- def logical_not(x, /, out=None, queue=None):
3183
+ def logical_not(x, /, out=None, queue: cl.CommandQueue | None = None):
3153
3184
  """
3154
3185
  Returns the element-wise logical NOT of *x*.
3155
3186
  """
@@ -3171,11 +3202,16 @@ def logical_not(x, /, out=None, queue=None):
3171
3202
 
3172
3203
  # {{{ reductions
3173
3204
 
3174
- def sum(a, dtype=None, queue=None, slice=None, initial=np._NoValue):
3205
+ def sum(
3206
+ a,
3207
+ dtype=None,
3208
+ queue: cl.CommandQueue | None = None,
3209
+ slice=None,
3210
+ initial=_NoValue):
3175
3211
  """
3176
3212
  .. versionadded:: 2011.1
3177
3213
  """
3178
- if initial is not np._NoValue and not isinstance(initial, SCALAR_CLASSES):
3214
+ if initial is not _NoValue and not isinstance(initial, SCALAR_CLASSES):
3179
3215
  raise ValueError("'initial' is not a scalar")
3180
3216
 
3181
3217
  if dtype is not None:
@@ -3188,27 +3224,27 @@ def sum(a, dtype=None, queue=None, slice=None, initial=np._NoValue):
3188
3224
  result.add_event(event1)
3189
3225
 
3190
3226
  # NOTE: neutral element in `get_sum_kernel` is 0 by default
3191
- if initial is not np._NoValue:
3227
+ if initial is not _NoValue:
3192
3228
  result += a.dtype.type(initial)
3193
3229
 
3194
3230
  return result
3195
3231
 
3196
3232
 
3197
- def any(a, queue=None, wait_for=None):
3233
+ def any(a, queue: cl.CommandQueue | None = None, wait_for: cl.WaitList = None):
3198
3234
  if len(a) == 0:
3199
3235
  return _BOOL_DTYPE.type(False)
3200
3236
 
3201
3237
  return a.any(queue=queue, wait_for=wait_for)
3202
3238
 
3203
3239
 
3204
- def all(a, queue=None, wait_for=None):
3240
+ def all(a, queue: cl.CommandQueue | None = None, wait_for: cl.WaitList = None):
3205
3241
  if len(a) == 0:
3206
3242
  return _BOOL_DTYPE.type(True)
3207
3243
 
3208
3244
  return a.all(queue=queue, wait_for=wait_for)
3209
3245
 
3210
3246
 
3211
- def dot(a, b, dtype=None, queue=None, slice=None):
3247
+ def dot(a, b, dtype=None, queue: cl.CommandQueue | None = None, slice=None):
3212
3248
  """
3213
3249
  .. versionadded:: 2011.1
3214
3250
  """
@@ -3225,7 +3261,7 @@ def dot(a, b, dtype=None, queue=None, slice=None):
3225
3261
  return result
3226
3262
 
3227
3263
 
3228
- def vdot(a, b, dtype=None, queue=None, slice=None):
3264
+ def vdot(a, b, dtype=None, queue: cl.CommandQueue | None = None, slice=None):
3229
3265
  """Like :func:`numpy.vdot`.
3230
3266
 
3231
3267
  .. versionadded:: 2013.1
@@ -3244,7 +3280,13 @@ def vdot(a, b, dtype=None, queue=None, slice=None):
3244
3280
  return result
3245
3281
 
3246
3282
 
3247
- def subset_dot(subset, a, b, dtype=None, queue=None, slice=None):
3283
+ def subset_dot(
3284
+ subset,
3285
+ a,
3286
+ b,
3287
+ dtype=None,
3288
+ queue: cl.CommandQueue | None = None,
3289
+ slice=None):
3248
3290
  """
3249
3291
  .. versionadded:: 2011.1
3250
3292
  """
@@ -3263,19 +3305,19 @@ def subset_dot(subset, a, b, dtype=None, queue=None, slice=None):
3263
3305
 
3264
3306
 
3265
3307
  def _make_minmax_kernel(what):
3266
- def f(a, queue=None, initial=np._NoValue):
3308
+ def f(a, queue: cl.CommandQueue | None = None, initial=_NoValue):
3267
3309
  if isinstance(a, SCALAR_CLASSES):
3268
3310
  return np.array(a).dtype.type(a)
3269
3311
 
3270
3312
  if len(a) == 0:
3271
- if initial is np._NoValue:
3313
+ if initial is _NoValue:
3272
3314
  raise ValueError(
3273
3315
  f"zero-size array to reduction '{what}' "
3274
3316
  "which has no identity")
3275
3317
  else:
3276
3318
  return initial
3277
3319
 
3278
- if initial is not np._NoValue and not isinstance(initial, SCALAR_CLASSES):
3320
+ if initial is not _NoValue and not isinstance(initial, SCALAR_CLASSES):
3279
3321
  raise ValueError("'initial' is not a scalar")
3280
3322
 
3281
3323
  from pyopencl.reduction import get_minmax_kernel
@@ -3284,7 +3326,7 @@ def _make_minmax_kernel(what):
3284
3326
  return_event=True)
3285
3327
  result.add_event(event1)
3286
3328
 
3287
- if initial is not np._NoValue:
3329
+ if initial is not _NoValue:
3288
3330
  initial = a.dtype.type(initial)
3289
3331
  if what == "min":
3290
3332
  result = minimum(result, initial, queue=queue)
@@ -3312,7 +3354,7 @@ max.__doc__ = """
3312
3354
 
3313
3355
 
3314
3356
  def _make_subset_minmax_kernel(what):
3315
- def f(subset, a, queue=None, slice=None):
3357
+ def f(subset, a, queue: cl.CommandQueue | None = None, slice=None):
3316
3358
  from pyopencl.reduction import get_subset_minmax_kernel
3317
3359
  krnl = get_subset_minmax_kernel(a.context, what, a.dtype, subset.dtype)
3318
3360
  result, event1 = krnl(subset, a, queue=queue, slice=slice,
@@ -3332,8 +3374,8 @@ subset_max.__doc__ = """.. versionadded:: 2011.1"""
3332
3374
 
3333
3375
  # {{{ scans
3334
3376
 
3335
- def cumsum(a, output_dtype=None, queue=None,
3336
- wait_for=None, return_event=False):
3377
+ def cumsum(a, output_dtype=None, queue: cl.CommandQueue | None = None,
3378
+ wait_for: cl.WaitList = None, return_event=False):
3337
3379
  # undocumented for now
3338
3380
 
3339
3381
  """