在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产品,不存在于数字中。