英文:
tuple as output of @vectorize function (numba): what signature so I have to use?
问题
@vectorize((float64[:], float64[:])(float64[:]))
英文:
I am trying to create a vectorized function
@vectorize()
def rhou(f):
rho = numpy.sum(f, axis=-1)
u = 1.0
v = 2.0
w = 3.0
velocity = numpy.array([u,v,w])
return rho, velocity
rho
, f
, u
, v
, w
, and velocity
are all of the type float64
. f
is an numpy array of the form f[:,:,:,:]
. So the input array (being f
) can be an array of any size regarding the first three indexes. The sum is taken over the fourth in the function rhou
.
My question is: what signature should I put in @vectorize()
?
I have tried @vectorize((float 64, float64)(float64))
(and many other probably stupid attempts with Tuple
for example), but that does not work. The help page of numba deals with s single output, but in this case the function returns two results.
Thanks!
Tried many things, but nothing helps. The numba help page is not clear about multiple outputs
答案1
得分: 2
The vectorized
装饰器不支持多个输出(afaik),但你可以使用 guvectorize
以实现这一点。 guvectorize
更加灵活,但这也意味着你将需要提供更多关于形状和类型的信息。
但你的代码目前也不太清晰,而且没有提供任何示例输入,这使得无法运行。对任何数组应用 vectorized
就像其名称所示,将操作向量化,这意味着它将对输入中的每个条目执行逐元素计算。因此,你的 sum(f)
语句毫无意义,因为它总是对单个值求和。所以我预期你要么不想向量化(逐元素),要么不想求和,但从你的帖子中无法确定这一点。
下面的示例使用 guvectorize
显示了与我认为你试图实现的类似的内容,但我不确定。使用 guvectorize
,你将需要指定要保留的维度(在函数中“看到”),其他所有内容都将被向量化。默认假设是在“末尾”的剩余维度上向量化,但该函数将自动获得一个轴关键字(类似于Numpy的ufuncs),允许你更改它。
请注意,没有返回语句,输出数组是函数的参数,并且结果设置在这些数组上!这类似于大多数Numpy函数上的 out=
关键字。
我不知道有任何方法可以避免不传递一个虚拟输入来让Numba知道“m”的大小是多少(velocity
的形状),即使你明确提供了返回数组如上所示,这是必要的。
另一种编写方式是让Numba创建/分配输出数组。它可以做到这一点,因为签名中知道形状(从签名中),并且知道数据类型。但我经常看到有人尝试这样做,而不了解必须通过索引数组来设置结果(即使输出标量!)。特别是一开始,自己创建输出并将其明确传递给函数可能更直观。
但那会看起来像:
英文:
The vectorized
decorator does not support multiple outputs (afaik), but you can use guvectorize
in order to achieve this. The guvectorize
is more flexible, but that also means you'll have to specify a bit more information regarding shapes & types.
But your code is also unclear at the moment, and you don't provide any sample input making it impossible to run. Applying vectorized
on any array, will as the name suggests, vectorize the operation, meaning it will perform an element-wise calculation on each entry in the input individually. So that makes your sum(f)
statement meaningless, since it will always take the sum of a single value. So I expect you either don't want to vectorize (element-wise), or don't want to take the sum, but this is unclear from your post.
The example below using guvectorize
shows something similar as what I think you're trying to achieve, but I'm not sure. With guvectorize
you'll have to specify the dimensions you want to keep ("see" in the function), and everything else will be vectorized. The default assumption is to vecorize over remaining dimensions at the "end", but the function will automatically get an axis keyword (similar as Numpy ufuncs) that allows you to change that.
@guvectorize([
"void(float64[:], float64[:], float64[:], float64[:])"
], "(n),(m)->(),(m)")
def rhou(f, dummy, rho, velocity):
rho[0] = np.sum(f)
velocity[0] = 1.0
velocity[1] = 2.0
velocity[2] = 3.0
f = np.random.randn(3)
velocity = np.empty(3, dtype=np.float64)
rho = np.empty(1, dtype=np.float64)
rhou(f, velocity, rho, velocity)
Note how there is no return statement, the output arrays are arguments to the function, and the results as set on those! This is a similar pattern as the out=
keyword on most Numpy functions.
I don't know anyway to avoid having to pass a dummy input to let Numba know what the size of "m" is (shape of velocity
), this is necessary even if you provide the return array explicitly as shown above.
An alternative way of writing this is having Numba create/allocate the output arrays. It can do this because both the shape (from the signature) and the datatype is known. But I often see people who try this not realizing you have to set the result by indexing the array (even if you output a scalar!). Especially at first it's probably more intuitive to create the outputs yourself, and pass the explicitly to the function.
But that would look something like:
import numba; import numpy as np
@numba.guvectorize([
"void(float64[:], float64[:], float64[:], float64[:])",
], "(n),(m)->(),(m)")
def rhou(f, _, rho, velocity):
rho[0] = np.sum(f)
velocity[0] = 1.0
velocity[1] = 2.0
velocity[2] = 3.0
f = np.random.randn(3)
dummy = np.empty(3, dtype=np.float64)
rho, velocity = rhou(f, dummy)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论