Numpy has a basic pxd that declares its c interface to cython. Is there such a pxd for scipy components (especially scipy.integrate.quadpack)?
Alternatively, could someone give an example of how to link directly with c/fortran functions included in scipy from cython? So far I have always used pyximport … will that work here, or will I have to link using distutils (or make..)?
Thanks!
—- UPDATE —-
The cython 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’ve focused my problem on actually “pointing” my reference of fortran QDAGSE to the _quadpack.so in scipy.integrate. (N.B. tried lowercase version as well.)… without having to hack scipy by putting a pxd there. Is there some way I can do this? Perhaps dynamically? (Can I load the .so dynamically and bind the appropriate function pointer onto 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
Thanks to: http://codespeak.net/pipermail/cython-dev/2009-October/007239.html
Adapting, the following seems to work.
With this prepended, the code above seems to work… well except that, annoyingly enough, the answer is a bit different than the python quad, and also quadpack dblquad (I’m evaluating a double integral). I assume I either need more resolution, or need to specify a parameter with a non-default value. (Also it won’t port to Windows perhaps? But that would just mean changing “.so” to “.dll”)
It gets me just under 5x speed up from previous code that used python callback, but otherwise was as optimized as I could get it.
For extra credit… how do I smuggle in extra parameters to the c callback? I assume its impossible without global variables? or I could use weave?
In any case — thanks for your attention — this is an obscure example, but has more general applicability to calling undeclared c functions in extension modules from cython. If anyone has a more elegant way of doing it, I’d be eager to hear.