3

I'm using pybind to wrap C++ code.

Given the following function, which is originally part of a library and should not be modified:

void manipulate(Eigen::MatrixXd& data) {
    data = data*2;
}

Using pybind, I can wrap it as:

#include <pybind11/pybind11.h>
#include <pybind11/eigen.h>
#include <Eigen/LU>
namespace py = pybind11;

void wrap1(Eigen::Ref<Eigen::MatrixXd> data){
    Eigen::MatrixXd mData(data);
    manipulate(mData);
    data = mData;
}

PYBIND11_PLUGIN(cod) {
    pybind11::module m("cod", "auto-compiled c++ extension");
    m.def("wrap1", &wrap1);
    return m.ptr();
}

But this creates an unnecessary copy mData.

This fails to modify the data:

void wrap2(Eigen::MatrixXd& data){
    manipulate(data);
}

And this one fails fails to compile:

void wrap3(Eigen::Ref<Eigen::MatrixXd> data){
    manipulate(data);
}

How can I avoid creating a copy of data likewise wrap2, wrap3 or an equivalent of std::swap?

ilciavo
  • 3,069
  • 7
  • 26
  • 40

1 Answers1

0

This fails to modify the data:

void wrap2(Eigen::MatrixXd& data){

Yes, this won't modify the original numpy array because pybind must first copy it into a temporary Eigen matrix to call wrap2. From the pybind Eigen docs:

One major limitation of the above is that every data conversion implicitly involves a copy, which can be both expensive (for large matrices) and disallows binding functions that change their (Matrix) arguments. Pybind11 allows you to work around this by using Eigen’s Eigen::Ref class...

Therefore, we have to use Eigen::Ref.

And this one fails fails to compile:

void wrap3(Eigen::Ref<Eigen::MatrixXd> data){
    manipulate(data);
}

The solution is to define a function that accepts an Eigen::Ref:

void manipulate(Eigen::Ref<Eigen::MatrixXd> data) {
    data = data*2;
}

Another option is to make manipulate a function template. See Eigen's documentation on Writing Functions Taking Eigen Types as Parameters.

Lack
  • 1,625
  • 1
  • 17
  • 29