简体   繁体   中英

Passing a numpy function in python to C++ using SWIG directors

My code is mainly in C++, but I want to use the SWIG director option to redefine a C++ virtual function in python, and then pass that function back to C++. The following is a simplified example.

Here is my base class in C++ with a virtual function fun . fun takes in (double* x, int n) which allows me to pass a numpy array into it.

class base{
public:
    virtual double fun(double* x, int n){return 0.0;}
};

I have another class which takes in this base class:

class main{
public:
    base* b_;

    main(base& b){
        b_ = &b; 
    }
};

This class has a constructor which takes in a base class and stores a pointer to it ( b_ ).

I can successfully compile the swig interface into a module named mymodule making sure to enable directors (see SWIG interface file below), and, as per the SWIG director documentation, I inherit the base class and redefine the virtual function fun as follows:

import mymodule
class base(mymodule.base):
    def __init__(self):
        super(base,self).__init__()
    def fun(self,x):
        return x[0]

Then I pass it into the main class:

b = base()
m = mymodule.main(b)

However, when I try m.b_.fun(array([1.,2.])) I get a TypeError :

TypeError: 'SwigPyObject' object has no attribute '__getitem__'

Any ideas on how to get this to work? I think when I pass b into mymodule.main, C++ is seeing x as a double * pointer and doesn't know what to do with it.

By the way, here is my swig interface file:

%module(directors="1") mymodule

%{
#define SWIG_FILE_WITH_INIT
/* Includes the header in the wrapper code */
#include "myclasses.h"
%}

%feature("director") base;

%init %{
import_array();
%}

%apply (double* IN_ARRAY1, int DIM1) {(double* x, int n)};

/* Parse the header file to generate wrappers */
%include "myclasses.h"

It looks like an ownership issue from Python.

Provide a hint to SWIG:

%new double *fun(double* IN_ARRAY1, int DIM1) {(double* x, int n)};

Notice the pointer to the function itself as well. The Python module will assign proper ownership of the object(s) when %new is used. That's why you can use values but not variables in the call.

It seems that director isn't recognizing your Python implementation of fun(double* x, int n) ; it's not doing the overloading of that function.

I suspect that the reason is due to of the fact that your Python implementation uses numpy as argument. Please note that the director will call either the abstract function or the implemented one.

On the other hand, %apply (double* IN_ARRAY1, int DIM1) {(double* x, int n)} only declares the typemap logic for wrapping the function in Python, not to the director. Note that this is the reason why b.fun(array([1.,2.]) works! Said that, you should declare the typemap logic to the director.

Here you can find how to do it:

%typemap(directorin,numinputs=1) (double *x, int n)
{
    npy_intp dim = $2;
    $input = PyArray_SimpleNewFromData(1, &dim, NPY_DOUBLE, (void *)$1);
}

Hope that this solves your problem and other futures ones :). I got a similar issue and spent few days trying to figure out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM