我已经仔细阅读了笨拙的 1 存储库中的文档和演示笔记本(我完全有可能错过了一些明显的东西),但是我误入了陌生的领域,希望得到一些帮助。
假设我在极坐标系中有点,我使用尴尬1 库将这些点作为记录数组提供给用户。一些用户可能更喜欢使用笛卡尔坐标系中的点,因此我可以通过添加行为来适应它们,以下示例有效。
import awkward1 as ak
import numpy as np
class Polar2Cartesian(object):
"""Mixin class to convert from polar to Cartesian."""
@property
def x(self):
return self.r * np.cos(self.theta)
# And similarly for y, but this is just an example
# Register the behaviors with awkward
class Point(ak.Record, Polar2Cartesian):
pass
class PointArray(ak.Array, Polar2Cartesian):
pass
ak.behavior['Point'] = Point
ak.behavior['*', 'Point'] = PointArray
# Define the points
r = np.array([2.53, 0.29, 3.18])
theta = np.array([np.pi/4, np.pi, -np.pi/3])
points = ak.zip({'r': r, 'theta': theta}, with_name='Point')
# x-component of the first point
points[0].x == r[0] * np.cos(theta[0]) # True
# x-components of all points
points.x == r * np.cos(theta) # <Array [True, True, True] type='3 * bool'>
现在假设转换必须使用 Numba 编译的函数。我在以下示例中定义了一个,但原则上它可能来自我无法控制的第三方库。以下适用于单个记录,但会在记录数组上引发 TypingError。
import awkward1 as ak
import numba as nb
import numpy as np
@nb.njit
def cos(x):
"""A contrived example appears."""
return np.cos(x)
class Polar2Cartesian(object):
"""Mixin class to convert from polar to Cartesian."""
@property
def x(self):
return self.r * cos(self.theta) # uses jitted function here
# And similarly for y, but this is just an example
# Define and register the behaviors like before, and create
# the same array of Points as in the previous example
# This still works
points[0].x == r[0] * np.cos(theta[0]) # True
# This now raises a TypingError
points.x == r * np.cos(theta)
解析回溯揭示了 TypingError 的原因:
TypingError: can't resolve ufunc cos for types (awkward1.ArrayView(awkward1.NumpyArrayType(array(float64, 1d, A), none, {}), None, ()),)
这是公平的,因为期望 Numba 在没有开发人员帮助的情况下知道如何使用这种类型是不合理的。
我发现的一种解决方法是np.asarray()
在 的定义内调用Polar2Cartesian.x
,即cos(np.asarray(self.theta))
。虽然cos
返回一个 NumPy 数组,Polar2Cartesian.x
但由于随后与self.r
. 一般来说,可以根据需要将返回值转换为不合适的记录或数组。
但是这个解决方案是“awkward1-approved”,还是我应该走我为 theta 和 x 提供 typer 和 lower 函数作为附加行为的路线?如果是后者,有人可以指导我如何正确编写 typer 和 lower 函数吗?
在这一点上,我想知道我的问题标题的范围是否过于广泛。如果有人有更好的建议,请告诉我。