我发现同时使用结构体和np非常方便。ndarray使用dtypes,如pyopencl.cltypes.float2。这是一种清晰且自我记录的方式,可以将结构化数据传递给我的内核,而不仅仅是一堆浮点数。
然而,我发现某些行为不方便。例如给定:
import numpy as np
import pyopencl.cltypes as cltp
a = np.zeros((3,5), dtype=cltp.float2)
>>> a
array([[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)]],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
在将数据结构传递给内核之前,我可以分段地构建数据结构,例如:
a[:,1] = (42,-42)
>>> a
array([[( 0., 0.), (42., -42.), ( 0., 0.), ( 0., 0.), ( 0., 0.)],
[( 0., 0.), (42., -42.), ( 0., 0.), ( 0., 0.), ( 0., 0.)],
[( 0., 0.), (42., -42.), ( 0., 0.), ( 0., 0.), ( 0., 0.)]],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
很好。然而,我也想将大小为2的数组赋值给float2,但这失败了。
a[:,1] = np.array((42,-42))
ValueError: could not broadcast input array from shape (2) into shape (3)
,我不得不求助于这个
a[:,1]['x'] = 42
a[:,1]['y'] = -42
可以工作,但是有点违背了整个事情的目的。
我错过了一些明显的语法差异,还是这个功能只是不应该这样使用?
编辑:在我试图给出最简单的例子时,我过度简化了这个问题。hpaulj的答案是正确的,因为如果我在形状=(2)的东西上使用显式dtype=float2,它将被转换为形状=(1,)的dtype=float2。然而,我的实际问题更一般,关于如何从一个数组(shape=(foo, bar, N), dtype=np.float32)到一个数组(shape=(foo, bar), dtype=cltp.floatN), N=2,3,4。
刚才出现的后续问题:是否需要进行实际的复制,或者是否可以"就地"转换?实际的内存布局乍一看是兼容的。
In [99]: a=np.array([[(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
...: [(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)],
...: [(0., 0.), (0., 0.), (0., 0.), (0., 0.), (0., 0.)]],
...: dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
In [100]: a.dtype
Out[100]: dtype([(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
In [101]: a.dtype.fields
Out[101]:
mappingproxy({'s0': (dtype('float32'), 0, 'x'),
'x': (dtype('float32'), 0, 'x'),
's1': (dtype('float32'), 4, 'y'),
'y': (dtype('float32'), 4, 'y')})
看一下预期的目标,一个3个元素的数组,复合dtype:
In [102]: a[:,1]
Out[102]:
array([(0., 0.), (0., 0.), (0., 0.)],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
当你的数组是2个元素的整型时。对于这种结构,使用元组不会改变任何东西。
In [103]: np.array((42,-42))
Out[103]: array([ 42, -42])
但是如果指定了正确的dtype,则创建了一个0d数组:
In [104]: np.array((42,-42), a.dtype)
Out[104]: array((42., -42.), dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
现在赋值是没有问题的
In [105]: a[:,1] = np.array((42,-42), a.dtype)
编辑
In [3]: dt = a.dtype
In [4]: dt
Out[4]: dtype([(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
使用最近的recfunctions
添加,我们可以从形状适当的非结构化数组中生成结构化数组:
In [5]: import numpy.lib.recfunctions as rf
2d to 1d structured:
In [7]: rf.unstructured_to_structured(np.arange(1,7).reshape(3,2), dtype=dt)
Out[7]:
array([(1., 2.), (3., 4.), (5., 6.)],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
3d到2d结构:
In [8]: rf.unstructured_to_structured(np.arange(24).reshape(4,3,2), dtype=dt)
Out[8]:
array([[( 0., 1.), ( 2., 3.), ( 4., 5.)],
[( 6., 7.), ( 8., 9.), (10., 11.)],
[(12., 13.), (14., 15.), (16., 17.)],
[(18., 19.), (20., 21.), (22., 23.)]],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
或者从元组列表创建数组:
In [10]: np.array([(0,1),(2,3)], dt)
Out[10]:
array([(0., 1.), (2., 3.)],
dtype=[(('x', 's0'), '<f4'), (('y', 's1'), '<f4')])
recfunctions
经常使用逐字段设置:
In [16]: for name in a.dtype.names:
...: a[name][:] = np.arange(15).reshape(3,5)