Generalized Universal Functions¶
通常需要循环不仅是标量上的函数,而且还包括向量(或数组)上的函数,如http://scipy.org/scipy/numpy/wiki/GeneralLoopingFunctions上所述。我们建议通过泛化通用函数(ufuncs)来实现这个概念,并提供一个C语言实现,在numpy代码库中增加约500行。在当前(专用)ufunc中,基本函数限于逐元素操作,而通用版本通过“子数组”操作支持“子数组”。Perl向量库PDL提供了类似的功能,其术语在下面被重复使用。
每个广义ufunc具有与其相关联的信息,其具有输入的“核心”维度以及输出的对应维度(元素方式ufunc具有零核心维度)。所有参数的核心维度列表称为ufunc的“签名”。例如,ufunc numpy.add具有定义两个标量输入和一个标量输出的签名(),()->()
。
另一个例子是(见GeneralLoopingFunctions页)具有签名(i),(i)->()
的函数inner1d(a,b)
这将沿着每个输入的最后一个轴应用内积,但保持其余索引完整。For example, where a
is of shape (3,5,N)
and b
is of shape (5,N)
, this will return an output of shape (3,5)
. 基本的基本函数称为3×5次。在签名中,我们为每个输入指定一个核心维度(i)
,对于输出指定零个核心维度()
,因为它需要两个1-d数组,标量。通过使用相同的名称i
,我们指定两个对应的维度应该具有相同的大小(或其中一个大小为1,并且将被广播)。
超过核心尺寸的尺寸称为“环”尺寸。在上述示例中,这对应于(3,5)
。
通常的numpy“广播”规则适用,其中签名确定每个输入/输出对象的维度如何分裂为核心和环路维度:
- 虽然输入数组具有比相应数量的核心维度更小的维度,但是1是预先考虑其形状。
- 核心尺寸从所有输入中删除,剩余尺寸被广播;定义环路尺寸。
- 输出由环尺寸加上输出芯尺寸给出。
Definitions¶
- 基本功能
- 每个ufunc由一个基本函数组成,该函数对数组参数的最小部分执行最基本的操作(例如,添加两个数字是添加两个数组的最基本的操作)。ufunc在数组的不同部分上多次应用基本函数。基本函数的输入/输出可以是向量;例如,inner1d的基本函数采用两个向量作为输入。
- 签名
- 签名是描述ufunc的基本函数的输入/输出维度的字符串。有关详细信息,请参阅下面的部分。
- 核心维度
- 基本函数的每个输入/输出的维数由其核心维度(零核心维度对应于标量输入/输出)来定义。核心维度映射到输入/输出数组的最后一个维度。
- 维度名称
- 维度名称表示签名中的核心维度。不同的维度可以共享名称,指示它们具有相同的大小(或可广播)。
- 维度索引
- 维度索引是表示维度名称的整数。它根据签名中每个名称第一次出现的顺序枚举维名称。
Details of Signature¶
签名定义了输入和输出变量的“核心”维度,从而也定义了维度的收缩。签名由以下格式的字符串表示:
- 每个输入或输出数组的核心维度由括号中的维名称列表
(i_1,...,i_N)
表示;标量输入/输出由()
表示。代替i_1
,i_2
等,可以使用任何有效的Python变量名称。 - 不同参数的维列表由
","
“分隔。输入/输出参数由"->"
分隔。 - 如果在多个位置使用相同的维度名称,这将强制相同维度的大小(或可广播的大小)。
签名的形式语法如下:
<Signature> ::= <Input arguments> "->" <Output arguments>
<Input arguments> ::= <Argument list>
<Output arguments> ::= <Argument list>
<Argument list> ::= nil | <Argument> | <Argument> "," <Argument list>
<Argument> ::= "(" <Core dimension list> ")"
<Core dimension list> ::= nil | <Dimension name> |
<Dimension name> "," <Core dimension list>
<Dimension name> ::= valid Python variable name
笔记:
- 所有报价都是为了清楚。
- 共享相同名称的核心维度必须可以广播,如上面示例中的两个
i
。每个维度名称通常对应于基本函数实现中的一个循环级。 - 空白被忽略。
这里有一些签名的例子:
加 | (),()->() |
|
inner1d | (i),(i)->() |
|
sum1d | (i)->() |
|
dot2d | (m,n),(n,p)->(m,p) |
矩阵乘法 |
outer_inner | (i,t),(j,t)->(i,j) |
内部在最后一维,外部在第二到最后,和循环/广播在休息。 |
C-API for implementing Elementary Functions¶
当前接口保持不变,并且PyUFunc_FromFuncAndData
仍然可以用于实现(专用)ufunc,由标量基本函数组成。
可以使用PyUFunc_FromFuncAndDataAndSignature
来声明一个更通用的ufunc。参数列表与PyUFunc_FromFuncAndData
相同,还有一个参数将签名指定为C字符串。
此外,回调函数的类型与之前相同,void (* foo)(char ** args, intp * dimensions, intp * steps, void * func) t9>
。当调用时,args
是包含所有输入/输出参数的数据的长度nargs
的列表。对于标量基本函数,steps
也具有长度nargs
,表示用于参数的步幅。dimensions
是指向定义要循环的轴的大小的单个整数的指针。
对于非平凡签名,dimensions
也将包含核心维度的大小,从第二个条目开始。每个唯一维度名称仅提供一个大小,并且大小根据签名中维度名称的第一次出现而给出。
steps
的第一个nargs
元素保持与标量ufuncs相同。以下元素按顺序包含所有参数的所有核心维度的步长。
例如,考虑具有签名(i,j),(i)->()
的ufunc。In this case, args
will contain three pointers to the data of the input/output arrays a
, b
, c
. Furthermore, dimensions
will be [N, I, J]
to define the size of N
of the loop and the sizes I
and J
for the core dimensions i
and j
. 最后,steps
将是[a_N, b_N, c_N, a_i, t6> a_j, b_i]
,包含所有必要的步幅。