How to use scipy.integrate.quadpack (or other c / fortran in scipy) directly like cc cython

Numpy has a basic pxd that declares the cython c interface. Is there such a pxd for scipy components (especially scipy.integrate.quadpack)?

Alternatively, can anyone provide an example of how to directly link to the c / fortran functions included in scipy from cython? So far I've always used pyximport ... will this work here, or will I have to bundle using distutils (or make ..)?

Thank!

---- UPDATE ----

The code below compiles; however i get

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']

So, I think I focused my task on actually "pointing" my fortran QDAGSE link to _quadpack.so in scipy.integrate. (NB tried the lowercase version too.) ... without having to hack scipy by putting pxd in there. Is there a way to do this? Perhaps dynamically? (Can I load the .so dynamically and bind the appropriate function pointer to a global variable, perhaps?)

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

      

+3


source to share


1 answer


Thanks to: http://codespeak.net/pipermail/cython-dev/2009-October/007239.html

The adaptation seems to be working.

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 ]

      

With this addition, the code above seems to work ... well, except, annoyingly, the answer is slightly different from python square, and also quadpack dblquad (I am evaluating the double integral). I am guessing that I need more resolution or need to specify a parameter with a non-standard value. (Also it won't port to Windows, maybe? But that would mean changing ".so" to ".dll")



This gives me a little less than 5x speedup over previous code that used a python callback but was otherwise as optimized as I could get it.

For extra credit ... how do I pass additional parameters for the c callback? I assume its not possible without global variables? or could I use weave?

Anyway - thanks for your attention - this is an obscure example, but has more general applicability for calling undeclared c functions in extension modules from cython. If anyone has a more elegant way of doing this, I'd really love to hear.

+3


source







All Articles