78
78
name = "%s%d" % (base_name, count)
80
80
titles = field_names[:count]
81
if len(titles) < count:
82
titles.extend((count-len(titles))*[None])
86
names = ["s%d" % i for i in range(count)]
87
while len(names) < padded_count:
88
names.append("padding%d" % (len(names)-count))
90
if len(titles) < len(names):
91
titles.extend((len(names)-len(titles))*[None])
84
93
dtype = np.dtype(dict(
85
names=["s%d" % i for i in range(count)],
86
formats=[base_type]*count,
95
formats=[base_type]*padded_count,
89
98
get_or_register_dtype(name, dtype)
350
363
.. automethod :: __getitem__
351
364
.. automethod :: __setitem__
366
.. automethod :: setitem
368
.. automethod :: map_to_host
370
.. rubric:: Comparisons, conditionals, any, all
372
.. versionadded:: 2013.2
374
Boolean arrays are stored as :class:`numpy.int8` because ``bool``
375
has an unspecified size in the OpenCL spec.
377
.. automethod :: __nonzero__
379
Only works for device scalars. (i.e. "arrays" with ``shape == ()``.)
384
.. automethod :: __eq__
385
.. automethod :: __ne__
386
.. automethod :: __lt__
387
.. automethod :: __le__
388
.. automethod :: __gt__
389
.. automethod :: __ge__
355
__array_priority__ = 10
392
__array_priority__ = 100
357
394
def __init__(self, cqa, shape, dtype, order="C", allocator=None,
358
395
data=None, offset=0, queue=None, strides=None, events=None):
620
665
@elwise_kernel_runner
621
666
def _axpbz(out, a, x, b, queue=None):
622
"""Compute ``z = a * x + b``, where `b` is a scalar."""
667
"""Compute ``z = a * x + b``, where *b* is a scalar."""
670
assert out.shape == x.shape
625
671
return elementwise.get_axpbz_kernel(out.context,
626
672
a.dtype, x.dtype, b.dtype, out.dtype)
629
675
@elwise_kernel_runner
630
676
def _elwise_multiply(out, a, b, queue=None):
677
assert out.shape == a.shape
678
assert out.shape == b.shape
631
679
return elementwise.get_multiply_kernel(
632
680
a.context, a.dtype, b.dtype, out.dtype)
977
1026
self._copy(result, self, queue=queue)
980
# {{{ rich comparisons (or rather, lack thereof)
1029
# {{{ rich comparisons, any, all
1031
def __nonzero__(self):
1032
if self.shape == ():
1033
return bool(self.get())
1035
raise ValueError("The truth value of an array with "
1036
"more than one element is ambiguous. Use a.any() or a.all()")
1038
def any(self, queue=None, wait_for=None):
1039
from pyopencl.reduction import get_any_kernel
1040
krnl = get_any_kernel(self.context, self.dtype)
1041
return krnl(self, queue=queue, wait_for=wait_for)
1043
def all(self, queue=None, wait_for=None):
1044
from pyopencl.reduction import get_all_kernel
1045
krnl = get_all_kernel(self.context, self.dtype)
1046
return krnl(self, queue=queue, wait_for=wait_for)
1049
@elwise_kernel_runner
1050
def _scalar_comparison(out, a, b, queue=None, op=None):
1051
return elementwise.get_array_scalar_comparison_kernel(
1052
out.context, op, a.dtype)
1055
@elwise_kernel_runner
1056
def _array_comparison(out, a, b, queue=None, op=None):
1057
if a.shape != b.shape:
1058
raise ValueError("shapes of comparison arguments do not match")
1059
return elementwise.get_array_comparison_kernel(
1060
out.context, op, a.dtype, b.dtype)
982
1062
def __eq__(self, other):
983
raise NotImplementedError
1063
if isinstance(other, Array):
1064
result = self._new_like_me(np.int8)
1065
self._array_comparison(result, self, other, op="==")
1068
result = self._new_like_me(np.int8)
1069
self._scalar_comparison(result, self, other, op="==")
985
1072
def __ne__(self, other):
986
raise NotImplementedError
1073
if isinstance(other, Array):
1074
result = self._new_like_me(np.int8)
1075
self._array_comparison(result, self, other, op="!=")
1078
result = self._new_like_me(np.int8)
1079
self._scalar_comparison(result, self, other, op="!=")
988
1082
def __le__(self, other):
989
raise NotImplementedError
1083
if isinstance(other, Array):
1084
result = self._new_like_me(np.int8)
1085
self._array_comparison(result, self, other, op="<=")
1088
result = self._new_like_me(np.int8)
1089
self._scalar_comparison(result, self, other, op="<=")
991
1092
def __ge__(self, other):
992
raise NotImplementedError
1093
if isinstance(other, Array):
1094
result = self._new_like_me(np.int8)
1095
self._array_comparison(result, self, other, op=">=")
1098
result = self._new_like_me(np.int8)
1099
self._scalar_comparison(result, self, other, op=">=")
994
1102
def __lt__(self, other):
995
raise NotImplementedError
1103
if isinstance(other, Array):
1104
result = self._new_like_me(np.int8)
1105
self._array_comparison(result, self, other, op="<")
1108
result = self._new_like_me(np.int8)
1109
self._scalar_comparison(result, self, other, op="<")
997
1112
def __gt__(self, other):
998
raise NotImplementedError
1113
if isinstance(other, Array):
1114
result = self._new_like_me(np.int8)
1115
self._array_comparison(result, self, other, op=">")
1118
result = self._new_like_me(np.int8)
1119
self._scalar_comparison(result, self, other, op=">")
1066
1188
old_itemsize = self.dtype.itemsize
1067
1189
itemsize = np.dtype(dtype).itemsize
1069
if self.shape[-1] * old_itemsize % itemsize != 0:
1191
from pytools import argmin2
1192
min_stride_axis = argmin2(
1194
for axis, stride in enumerate(self.strides))
1196
if self.shape[min_stride_axis] * old_itemsize % itemsize != 0:
1070
1197
raise ValueError("new type not compatible with array")
1072
shape = self.shape[:-1] + (self.shape[-1] * old_itemsize // itemsize,)
1074
s * itemsize // old_itemsize
1075
for s in self.strides)
1200
self.shape[:min_stride_axis]
1201
+ (self.shape[min_stride_axis] * old_itemsize // itemsize,)
1202
+ self.shape[min_stride_axis+1:])
1204
self.strides[:min_stride_axis]
1205
+ (self.strides[min_stride_axis] * itemsize // old_itemsize,)
1206
+ self.strides[min_stride_axis+1:])
1077
1208
return self._new_with_changes(
1078
1209
self.base_data, self.offset,
1079
shape=shape, dtype=dtype,
1210
shape=new_shape, dtype=dtype,
1211
strides=new_strides)
1084
1215
def finish(self):
1086
cl.wait_for_events(self.events)
1218
cl.wait_for_events(self.events)
1221
def map_to_host(self, queue=None, flags=None, is_blocking=True, wait_for=None):
1222
"""If *is_blocking*, return a :class:`numpy.ndarray` corresponding to the
1223
same memory as *self*.
1225
If *is_blocking* is not true, return a tuple ``(ary, evt)``, where
1226
*ary* is the above-mentioned array.
1228
The host array is obtained using :func:`pyopencl.enqueue_map_buffer`.
1229
See there for further details.
1231
:arg flags: A combination of :class:`pyopencl.map_flags`.
1232
Defaults to read-write.
1234
.. versionadded :: 2013.2
1238
flags = cl.map_flags.READ | cl.map_flags.WRITE
1240
ary, evt = cl.enqueue_map_buffer(
1241
queue or self.queue, self.base_data, flags, self.offset,
1242
self.shape, self.dtype, strides=self.strides, wait_for=wait_for,
1243
is_blocking=is_blocking)
1250
# {{{ getitem/setitem
1089
1252
def __getitem__(self, index):
1091
1254
.. versionadded:: 2013.1
1257
if isinstance(index, Array):
1258
if index.dtype.kind != "i":
1260
"fancy indexing is only allowed with integers")
1261
if len(index.shape) != 1:
1262
raise NotImplementedError(
1263
"multidimensional fancy indexing is not supported")
1264
if len(self.shape) != 1:
1265
raise NotImplementedError(
1266
"fancy indexing into a multi-d array is not supported")
1268
return take(self, index)
1093
1270
if not isinstance(index, tuple):
1094
1271
index = (index,)
1165
1342
shape=tuple(new_shape),
1166
1343
strides=tuple(new_strides))
1168
def __setitem__(self, subscript, value):
1169
"""Set the slice of *self* identified *subscript* to *value*.
1171
*value* is allowed to be:
1173
* A :class:`Array` of the same :attr:`shape` and (for now) :attr:`strides`,
1174
but with potentially different :attr:`dtype`.
1175
* A :class:`numpy.ndarray` of the same :attr:`shape` and (for now)
1176
:attr:`strides`, but with potentially different :attr:`dtype`.
1179
Non-scalar broadcasting is not currently supported.
1345
def setitem(self, subscript, value, queue=None):
1346
"""Like :meth:`__setitem__`, but with the ability to specify
1347
a *queue* for execution.
1181
1349
.. versionadded:: 2013.1
1352
if isinstance(subscript, Array):
1353
if subscript.dtype.kind != "i":
1355
"fancy indexing is only allowed with integers")
1356
if len(subscript.shape) != 1:
1357
raise NotImplementedError(
1358
"multidimensional fancy indexing is not supported")
1359
if len(self.shape) != 1:
1360
raise NotImplementedError(
1361
"fancy indexing into a multi-d array is supported")
1363
multi_put([value], subscript, out=[self], queue=self.queue)
1366
queue = queue or self.queue or value.queue
1184
1368
subarray = self[subscript]
1186
1370
if isinstance(value, np.ndarray):
1187
1371
if subarray.shape == value.shape and subarray.strides == value.strides:
1188
1372
self.events.append(
1189
cl.enqueue_copy(self.queue, subarray.base_data,
1373
cl.enqueue_copy(queue, subarray.base_data,
1190
1374
value, device_offset=subarray.offset))
1193
value = to_device(self.queue, value, self.allocator)
1377
value = to_device(queue, value, self.allocator)
1195
1379
if isinstance(value, Array):
1196
1380
if len(subarray.shape) != len(value.shape):
1203
1387
raise ValueError("cannot assign between arrays of "
1204
1388
"differing strides")
1206
self._copy(subarray, value)
1390
self._copy(subarray, value, queue=queue)
1209
1393
# Let's assume it's a scalar
1210
subarray.fill(value)
1394
subarray.fill(value, queue=queue)
1396
def __setitem__(self, subscript, value):
1397
"""Set the slice of *self* identified *subscript* to *value*.
1399
*value* is allowed to be:
1401
* A :class:`Array` of the same :attr:`shape` and (for now) :attr:`strides`,
1402
but with potentially different :attr:`dtype`.
1403
* A :class:`numpy.ndarray` of the same :attr:`shape` and (for now)
1404
:attr:`strides`, but with potentially different :attr:`dtype`.
1407
Non-scalar broadcasting is not currently supported.
1409
.. versionadded:: 2013.1
1411
self.setitem(subscript, value)
1812
def concatenate(arrays, axis=0, queue=None, allocator=None):
1814
.. versionadded:: 2013.1
1816
# {{{ find properties of result array
1820
for i_ary, ary in enumerate(arrays):
1821
queue = queue or ary.queue
1822
allocator = allocator or ary.allocator
1826
shape = list(ary.shape)
1828
if len(ary.shape) != len(shape):
1829
raise ValueError("%d'th array has different number of axes "
1830
"(shold have %d, has %d)"
1831
% (i_ary, len(ary.shape), len(shape)))
1833
ary_shape_list = list(ary.shape)
1834
if (ary_shape_list[:axis] != shape[:axis]
1835
or ary_shape_list[axis+1:] != shape[axis+1:]):
1836
raise ValueError("%d'th array has residual not matching "
1837
"other arrays" % i_ary)
1839
shape[axis] += ary.shape[axis]
1843
shape = tuple(shape)
1844
dtype = np.find_common_type([ary.dtype for ary in arrays], [])
1845
result = empty(queue, shape, dtype, allocator=allocator)
1847
full_slice = (slice(None),) * len(shape)
1851
my_len = ary.shape[axis]
1854
+ (slice(base_idx, base_idx+my_len),)
1855
+ full_slice[axis+1:],
1863
@elwise_kernel_runner
1864
def _diff(result, array):
1865
return elementwise.get_diff_kernel(array.context, array.dtype)
1868
def diff(array, queue=None, allocator=None):
1870
.. versionadded:: 2013.2
1873
if len(array.shape) != 1:
1874
raise ValueError("multi-D arrays are not supported")
1878
queue = queue or array.queue
1879
allocator = allocator or array.allocator
1881
result = empty(queue, (n-1,), array.dtype, allocator=allocator)
1882
_diff(result, array, queue=queue)