简体   繁体   中英

Defining a C++ struct return type in Cython

I have written a small C++ library to simulate a system of ODEs, and have used Cython to wrap a function that initializes and solves the system. The C++ function takes in a handful of parameters, and returns a struct containing two matrices: a set of patterns used to construct the system, and the solved state of the system at every time step.

These matrices are implemented using the Eigen library, so I am using the Eigency interface to transfer the underlying contents of these data structures to NumPy arrays.

All is good if, in Python, I return a view to one of these matrices. However, I would like to return a tuple containing both of these matrices, which requires temporarily storing this struct, and then returning each of its matrix members:

## kernel.pyx

from eigency.core cimport *

cdef extern from "kernel_cpp.h":

  cdef cppclass network:
    MatrixXf state
    MatrixXf patterns

  cdef network _run "run" (int N, int K, int P, double g, double T, double tau, double dt)

def run(N=10000, K=100, P=30, g=1.5, T=0.5, tau=1e-3, dt=1e-3):
  return ndarray_view(_run(N,K,P,g,T,tau,dt).state) # <--- This works
  # This does not:
  # cdef network net = _run(N,K,P,g,T,tau,dt):
  # return (ndarray_view(net.state), ndarray_view(net.patterns))

The error that I get when building the commented code with python setup.py build_ext --inplace is

kernel.cpp:1552:11: error: no matching constructor for initialization of 'network'
  network __pyx_v_net;
          ^`

and this makes sense to me -- Cython is trying to call a constructor for network. But I want the construction to take place within "run." What is the correct type declaration here?

In case it helps, a stripped-down version of the code is here .

Thanks!

It's worth knowing how Cython translates code which stack allocates C++ variables:

def run(N=10000, K=100, P=30, g=1.5, T=0.5, tau=1e-3, dt=1e-3):
   cdef network net = _run(N,K,P,g,T,tau,dt)

the inside of the function gets translated to:

{
    // start of function
    network net; // actually some mangled variable name (see your error message)

    // body of function
    net = _run(N,K,P,g,T,tau,dt);
}

ie it requires both a default constructor and a copy/move assignment operator. This doesn't match how C++ code tends to be written so occasionally causes problems. Cython usually assumes the existence of these (unless you tell it about other constructors) so you don't need to explicitly write these out in your cdef cppclass block.

I think your error message looks to occur when compiling the C++ code and it's not defining a default constructor. (The copy assignment later shouldn't be a problem since C++ will automatically generate this). You have two options:

  1. If you're happy modifying the C++ code then define a default constructor. This will allow the Cython code to work as written. If you're using >=C++11 then that could be as easy as:

     network() = default; 

    It's possible that this won't work depending on whether the internal Eigen types can be default constructed though.

  2. If you don't want modify the C++ code, or if it turns out you can't easily define a default constructor, then you'll have to modify the Cython code to allocate the network with new . This also means you'll have to deal with deallocation yourself:

      # earlier cdef cppclass network: # need to tell Cython about copy constructor network(const network&) # everything else as before def run(N=10000, K=100, P=30, g=1.5, T=0.5, tau=1e-3, dt=1e-3): cdef network* net try: net = new network(_run(N,K,P,g,T,tau,dt)) return (ndarray_view(net.state), ndarray_view(net.patterns)) finally: del net 

    In this case no default constructor is needed, only a copy/move constructor (which you have to have anyway to be able to return a network from a function). Note use of finally to ensure than we free the memory.

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