如何直接使用scipy.integrate.quadpack(或scipy中的其他c / fortran)作为来自cython的c

时间:2012-04-02 20:52:55

标签: scipy cython

Numpy有一个基本的pxd,它声明了它与cython的c接口。 scipy组件是否有这样的pxd(特别是scipy.integrate.quadpack)?

或者,有人可以举例说明如何直接链接到cython中的scipy中包含的c / fortran函数吗?到目前为止,我一直使用pyximport ...这将在这里工作,还是我必须使用distutils(或make ..)进行链接?

谢谢!

----更新----

下面的cython代码编译;但是,我得到了

ImportError: Building module failed: ['ImportError: dlopen(/Users/shauncutts/.pyxbld/lib.macosx-10.7-intel-2.7/factfiber/stat/pmodel/c/meer.so, 2): Symbol not found: _DQAGSE\n Referenced from: /Users/shauncutts/.pyxbld/lib.macosx-10.7-intel-2.7/factfiber/stat/pmodel/c/meer.so\n Expected in: flat namespace\n in /Users/shauncutts/.pyxbld/lib.macosx-10.7-intel-2.7/factfiber/stat/pmodel/c/meer.so\n']

所以我认为我把我的问题集中在实际上“指向”我对fortin QDAGSE的引用到了scipy.integrate中的_quadpack.so。 (N.B.也试过小写版本。)...不必通过在那里放一个pxd来破解scipy。有什么方法可以做到这一点吗?也许动态? (我可以动态加载.so并将相应的函数指针绑定到全局变量上吗?)

cdef extern from "stdlib.h":
    void free(void* ptr)
    void* malloc(size_t size)
    void* realloc(void* ptr, size_t size)


ctypedef double (*qagfunc)( double* )

cdef extern:
    # in scipy.integrate._quadpack
    cdef void dqagse(
        qagfunc f, double *a, double *b, double *epsabs, double *epsrel,
        int *limit, 
        double *result, double *abserr, int *neval, int *ier,
        double *alist, double *blist, double *rlist, double *elist,
        int *iord, int *last
        )

class QAGError( ValueError ):
    code = None

cdef double qags( 
    qagfunc quad_function, double a, double b,
    double epsabs=1.49e-8, double epsrel=1.49e-8, 
    int limit = 50 
    ):

    '''
    wrapper for QUADPACK quags/quagse
    '''
    cdef double result, abserr
    cdef int neval = 0, ier = 0, last = 0
    cdef int *iord = <int *>malloc( limit * sizeof( double ) )
    cdef double *alist = <double *>malloc( limit * sizeof( double ) )
    cdef double *blist = <double *>malloc( limit * sizeof( double ) )
    cdef double *rlist = <double *>malloc( limit * sizeof( double ) )
    cdef double *elist = <double *>malloc( limit * sizeof( double ) )

    try:
        DQAGSE(
            quad_function, &a, &b, &epsabs, &epsrel, &limit, 
            &result, &abserr, &neval, &ier, 
            alist, blist, rlist, elist, iord, &last);

    finally:
        free( iord )
        free( alist )
        free( blist )
        free( rlist )
        free( elist )

    if ier > 0:
        raise QAGError( QUAGS_IER_MAP[ ier ] )
    return result

1 个答案:

答案 0 :(得分:3)

感谢:http://codespeak.net/pipermail/cython-dev/2009-October/007239.html

适应,以下似乎有效。

from os import path
import ctypes

from scipy.integrate import quadpack

ctypedef double (*qagfunc)( double* )

ctypedef void (*quadpack_qagse_fp)( 
    qagfunc f, double *a, double *b, double *epsabs, double *epsrel,
    int *limit, 
    double *result, double *abserr, int *neval, int *ier,
    double *alist, double *blist, double *rlist, double *elist,
    int *iord, int *last
    )

quadpack_path = path.dirname( quadpack.__file__ )
quadpack_ext_path = path.join( quadpack_path, '_quadpack.so' ) 
quadpack_lib = ctypes.CDLL( quadpack_ext_path )

cdef quadpack_qagse_fp quadpack_qagse
quadpack_qagse = ( 
    <quadpack_qagse_fp*><size_t> ctypes.addressof( quadpack_lib.dqagse_ ) )[ 0 ]

有了这个前置,上面的代码似乎工作......好吧,但是,令人讨厌的是,答案有点不同于python quad,还有quadpack dblquad(我正在评估一个双积分)。我假设我需要更多分辨率,或者需要使用非默认值指定参数。 (也许它不会移植到Windows?但这只是意味着将“.so”改为“.dll”)

它让我的速度比之前使用python回调的代码快了不到5倍,但其他方面都得到了优化,我可以得到它。

额外信用......如何将额外参数走私到c回调?我认为没有全局变量是不可能的?或者我可以使用编织?

无论如何 - 感谢您的关注 - 这是一个不起眼的例子,但更广泛地适用于从cython调用扩展模块中的未声明的c函数。如果有人有更优雅的方式,我会渴望听到。