Pergunta

I have the following Cython modules:

compmech    
    integrate
        integratev.pxd
        integratev.pyx
    conecyl
        main.pyx

In integratev.pxd I've declared:

ctypedef void (*f_type)(int npts, double *xs, double *ts, double *out,
                    double *alphas, double *betas, void *args) nogil

cdef int trapz2d(f_type f, int fdim, np.ndarray[cDOUBLE, ndim=1] final_out,
                 double xmin, double xmax, int m,
                 double ymin, double ymax, int n,
                 void *args, int num_cores)

I call trapz2d from main.pyx, and the function passed to trapz2d is declared in main.pyx, e.g:

from compmech.integrate.integratev cimport trapz2d

cdef void cfk0L(int npts, double *xs, double *ts, double *out,
                double *alphas, double *betas, void *args) nogil:
    ...

trapz2d(<f_type>cfk0L, fdim, k0Lv, xa, xb, nx, ta, tb, nt, &args, num_cores)

It compiles just fine, but when I run I get the error:

TypeError: C function compmech.integrate.integratev.trapz2d has wrong signature       
(expected int (__pyx_t_8compmech_9integrate_10integratev_f_type, int, PyArrayObject *,
               double, double, int, double, double, int, void *, int),
 got int (__pyx_t_10integratev_f_type, int, PyArrayObject *,
          double, double, int, double, double, int, void *, int))

It seems like a bug to me, but perhaps I am missing something important here...


Note: it works when I put everything inside main.pyx instead of using multiple modules.

Foi útil?

Solução

This does indeed seem like a bug where the automatic attempt to merge the types in filename.pxd and filename.pyx fails. Using void* is one workaround, but if you want to avoid casting, you can create a third file _util.pxd that contains the shared definition of the function pointer.

# _util.pxd

ctypedef void (*f_type)(int npts, double *xs, double *ts, double *out,
                        double *alphas, double *betas, void *args) nogil

And then you can import the shared typedef into both integrate.pxd and integrate.pyx which guarantees that the types are the same.

Outras dicas

The solution was to pass everything as void * and just cast to <f_type> before the function is actually executed, inside trapz2d(). The final layout of the code is:

ctypedef void (*f_type)(int npts, double *xs, double *ts, double *out,
                    double *alphas, double *betas, void *args) nogil

cdef int trapz2d(void *fin, int fdim, np.ndarray[cDOUBLE, ndim=1] final_out,
                 double xmin, double xmax, int m,
                 double ymin, double ymax, int n,
                 void *args, int num_cores)
    cdef f_type f
    f = <f_type>fin
    ...

and in the other code:

from compmech.integrate.integratev cimport trapz2d

cdef void cfk0L(int npts, double *xs, double *ts, double *out,
                double *alphas, double *betas, void *args) nogil:
    ...

trapz2d(<void *>cfk0L, fdim, k0Lv, xa, xb, nx, ta, tb, nt, &args, num_cores)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top