使用LAPACK分发基于Cython的扩展程序

68

我正在编写一个Python模块,其中包括Cython扩展,并使用LAPACK和BLAS。 我可以使用clapack或lapacke,或者如果必要,使用f2c或f2py解决方案。 重要的是我能够在紧密循环中从Cython调用lapack和blas例程而没有Python调用开销。

我发现了一个示例,链接在这里。 但是,该示例依赖于SAGE。 我希望我的模块可安装而无需安装SAGE,因为我的用户不太可能需要或想要安装SAGE以外的任何内容。 我的用户可能已经安装了像numpy、scipy、pandas和scikit-learn等软件包,因此它们将是合理的依赖项。 使用哪些界面的组合最佳,并且什么样的setup.py文件最小化可以获取(从numpy、scipy等)编译所需的信息?

编辑:以下是我最终采取的方法。 它在我的macbook上运行良好,但我不知道它有多少可移植性。 肯定有更好的方法。

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy
from Cython.Build import cythonize
from numpy.distutils.system_info import get_info

# TODO: This cannot be the right way
blas_include = get_info('blas_opt')['extra_compile_args'][1][2:]
includes = [blas_include,numpy.get_include()]

setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = cythonize([Extension("cylapack", ["cylapack.pyx"],
                                       include_dirs = includes,
                                       libraries=['blas','lapack'])
                   ])
)

这是因为在我的 MacBook 上,clapack.h 头文件与 cblas.h 处于同一目录下。然后我可以在我的 pyx 文件中这样做:

ctypedef np.int32_t integer

cdef extern from "cblas.h":
    double cblas_dnrm2(int N,double *X, int incX)
cdef extern from "clapack.h":
    integer dgelsy_(integer *m, integer *n, integer *nrhs, 
    double *a, integer *lda, double *b, integer *ldb, integer *
    jpvt, double *rcond, integer *rank, double *work, integer *
    lwork, integer *info)
1个回答

6
如果我正确理解了问题,您可以使用SciPy的Cython包装器来调用BLAS和LAPACK例程。这些包装器在此处有文档: 正如文档所述,您需要负责检查您传递给这些函数的任何数组是否对Fortran例程正确对齐。您可以在. pyx文件中简单地导入并根据需要使用这些函数。例如:
from scipy.linalg.cython_blas cimport dnrm2 
from scipy.linalg.cython_lapack cimport dgelsy 

考虑到这是经过充分测试、广泛使用且可以在不同平台上运行的代码,我认为它是可靠地分发直接调用BLAS和LAPACK例程的Cython扩展的好选择。
如果您不想让您的代码依赖于整个SciPy,您可以在SciPy的linalg目录这里找到许多相关的包装器函数文件。一个有用的参考是setup.py中的这些行,其中列出了源文件和头文件。请注意,需要Fortran编译器!
理论上讲,应该可以仅隔离此处所需的BLAS和LAPACK Cython包装器的源文件,然后将它们作为独立扩展与您的模块捆绑在一起。
在实践中,这样做非常繁琐。linalg子模块的构建过程需要一些Python函数来帮助在不同平台上进行编译(例如从here)。构建还依赖于其他C和Fortran源文件(here),这些文件的路径被硬编码到这些Python函数中。
显然,为了确保SciPy在不同的操作系统和架构上正确编译,已经付出了大量的工作。
我相信这是可能的,但是在移动文件并调整路径后,我尚未找到构建此部分linalg子模块而不依赖于SciPy其他部分的正确方式。如果我找到正确的方法,我一定会更新这个答案。

1
我的印象是,这个问题更多地涉及如何链接到随scipy/numpy一起提供的blas,并使其在多台计算机上(已安装scipy/numpy)正常工作,而无需在每台计算机上重新编译。但使用scipy提供的包装器的建议是好的。 - DavidW
啊,你可能是正确的。如果楼主提供进一步的澄清,我可以根据需要进行修改或删除这个答案(或将其转换为评论)。 - Alex Riley
这是一个很好的方法。@DavidW 是正确的,我正在寻找一种便携式解决方案,不需要用户安装额外的库。我认为通过适当的 setup.py 文件可以实现这些。ajcr,你能添加一个示例 setup.py 文件,展示如何获取任何必要的包含目录等吗?我认为 numpy.get_include() 就足够了? - jcrudy
值得注意的是,这是一个相对较新的功能,我认为在你提出问题时它还不存在(虽然这并不重要)。 - DavidW
2
对于那些稍后阅读此文的人,使用 SciPy 的包装器无需在 setup.py 文件中进行任何特殊操作。 - IanH
显示剩余8条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接