2.2.2.4 广义ufuncs
ufunc
output = elementwise_function(input)
output
和input
都可以只是一个数组元素。
广义ufunc
output
和input
可以是有固定维度数的数组
例如,矩阵迹(对象线元素的sum):
In [ ]:
input shape = (n, n)
output shape = () i.e. scalar
(n, n) -> ()
矩阵乘积:
In [ ]:
input_1 shape = (m, n)
input_2 shape = (n, p)
output shape = (m, p)
(m, n), (n, p) -> (m, p)
- 这是广义ufunc的”签名“
- g-ufunc发挥作用的维度是“核心维度”
Numpy中的状态
- g-ufuncs已经在Numpy中…
- 新的可以用
PyUFunc_FromFuncAndDataAndSignature
来创建 - … 但是,除了测试外,我们不会配置公用的g-ufuncs,ATM
In [4]:
import numpy.core.umath_tests as ut
ut.matrix_multiply.signature
Out[4]:
'(m,n),(n,p)->(m,p)'
In [5]:
x = np.ones((10, 2, 4))
y = np.ones((10, 4, 5))
ut.matrix_multiply(x, y).shape
Out[5]:
(10, 2, 5)
- 后两个维度成为了核心维度,并且根据每个签名去修改
- 否则,g-ufunc“按元素级”运行
- 这种方式的矩阵乘法对一次在许多小矩阵是非常有用
广义ufunc循环
矩阵相乘 (m,n),(n,p) -> (m,p)
In [ ]:
void gufunc_loop(void **args, int *dimensions, int *steps, void *data)
{
char *input_1 = (char*)args[0]; /* these are as previously */
char *input_2 = (char*)args[1];
char *output = (char*)args[2];
int input_1_stride_m = steps[3]; /* strides for the core dimensions */
int input_1_stride_n = steps[4]; /* are added after the non-core */
int input_2_strides_n = steps[5]; /* steps */
int input_2_strides_p = steps[6];
int output_strides_n = steps[7];
int output_strides_p = steps[8];
int m = dimension[1]; /* core dimensions are added after */
int n = dimension[2]; /* the main dimension; order as in */
int p = dimension[3]; /* signature */
int i;
for (i = 0; i < dimensions[0]; ++i) {
matmul_for_strided_matrices(input_1, input_2, output,
strides for each array...);
input_1 += steps[0];
input_2 += steps[1];
output += steps[2];
}
}