在Cython中调用点积和线性代数运算?
我正在尝试使用点积,matrix求逆和其他基本的线性代数运算,这些运算可以从Cython的numpy中获得。 函数如numpy.linalg.inv
(反转), numpy.dot
(点积), Xt
(matrix/数组的转置)。 调用numpy.*
有很大的开销,从Cython函数和其余的函数是用Cython编写的,所以我想避免这种情况。
如果我假设用户安装了numpy
,有没有办法做到这样的事情:
#include "numpy/npy_math.h"
作为一个extern
,并且调用这些函数? 或者直接调用BLAS(或者是这些核心操作的numpy调用)?
举一个例子,假设你在Cython中有一个函数做很多事情,最后需要做一个包含点积和matrix求逆的计算:
cdef myfunc(...): # ... do many things faster than Python could # ... # compute one value using dot products and inv # without using # import numpy as np # np.* val = gammaln(sum(v)) - sum(gammaln(v)) + dot((v - 1).T, log(x).T)
如何才能做到这一点? 如果有一个库已经在Cython中实现了,我也可以使用它,但没有find任何东西。 即使这些程序不是直接比BLAS优化的,也没有从Cython调用numpy
Python模块的开销,但仍然会使整体速度更快。
示例函数我想要调用:
- 点积(
np.dot
) - matrix求逆(
np.linalg.inv
) - matrix乘法
- 转置(相当于
xT
) - gammaln函数(如
scipy.gammaln
等价物,它应该在C中可用)
我意识到,它在numpy邮件列表( https://groups.google.com/forum/?fromgroups=#!topic/cython-users/XZjMVSIQnTE )上说,如果你在大型matrix中调用这些函数,没有任何意义从Cython做它,因为从numpy调用它只会导致大部分的时间花在优化的C代码,numpy调用。 然而,就我而言,我对这些小matrix上的这些线性代数运算有很多要求 – 在这种情况下,从Cython反复地返回numpy并返回到Cython引入的开销远远大于实际计算操作的时间BLAS。 因此,我想把这些简单的操作放在C / Cython级别,而不是通过python。
我不想通过GSL,因为这增加了另一个依赖,因为目前还不清楚GSL是否积极维护。 由于我假设代码的用户已经安装了scipy / numpy,所以我可以安全地假设他们有所有与这些库相关的关联C代码,所以我只想要能够使用该代码并调用它从Cython。
编辑 :我发现一个图书馆封装BLAS在Cython( https://github.com/tokyo/tokyo )这是接近,但不是我在找什么。 我想直接调用numpy / scipy C函数(我假设用户安装了这些)。
调用与Scipy捆绑在一起的BLAS是“相当”直接的,下面是调用DGEMM来计算matrix乘法的一个例子: https ://gist.github.com/pv/5437087 请注意,BLAS和LAPACK期望所有的数组都是Fortran连续的(模lda / b / c参数),因此order="F"
和double[::1,:]
是正确运行所需的。
计算逆可以通过在单位matrix上应用LAPACK函数dgesv
来类似地完成。 签名请看这里 。 所有这一切都需要下降到相当低层次的编码,你需要自己分配临时工作数组等等—但是这些可以被封装到自己的便利函数中,或者只是通过replacelib_*
函数来重复使用来自tokyo
的代码用上面的方式从Scipy获得函数指针。
如果你使用Cython的memoryview语法( double[::1,:]
),你的转置和往常一样。 或者,您可以通过编写自己的函数来计算转置,该函数可以跨越对angular线交换arrays的元素。 Numpy实际上并不包含这个操作, xT
只改变数组的步幅,不移动数据。
重写tokyo
模块可能会使用Scipy导出的BLAS / LAPACK,并将其捆绑在scipy.linalg
,以便您可以from scipy.linalg.blas cimport dgemm
。 如果有人想要接受请求,则接受请求 。
正如你所看到的,这一切都归结为传递函数指针。 如上所述,Cython实际上提供了自己的协议来交换函数指针。 举个例子, from scipy.spatial import qhull; print(qhull.__pyx_capi__)
from scipy.spatial import qhull; print(qhull.__pyx_capi__)
—这些函数可以通过from scipy.spatial.qhull cimport XXXX
来访问(它们是私有的,所以不要这样做)。
但是,目前, scipy.special
不提供这个C-API。 但是事实上,提供它会非常简单,因为scipy.special中的接口模块是用Cython编写的。
我不认为目前有任何一种理智和便携的方式来访问这个function,为gamln
做繁重的gamln
(虽然你可以窥探UFunc对象,但这不是一个理智的解决scheme:),所以目前可能最好只抓住scipy.special的源代码的相关部分,并将其捆绑到您的项目中,或使用例如GSL。
如果您接受使用GSL,最简单的方法可能是使用这个GSL-> cython接口https://github.com/twiecki/CythonGSL并从那里调用BLAS(请参阅示例https://github.com/twiecki /CythonGSL/blob/master/examples/blas2.pyx )。 它也应该照顾Fortran vs C的顺序。 GSL的新function并不多,但您可以放心地认为它是主动维护的。 与东京相比,CythonGSL更完整; 例如,它具有对称matrix产品,不存在于数字中。