Search code examples
pythonc++eigen3pybind11

Exporting Eigen csr_matrix to python via Pybind11 without converting to scipy.sparse.csc/csr matrix


I would like to export the eigen csr sparse matrix to python in order to perform benchmarks. I'm well aware that the scipy.sparse csr matrix is following the canonical format of a csr matrix, while eigen has a different representation, and that's specifically what I would like to play with.
However, when exporting the eigen csr matrix, pybind11 exports it as a scipy.sparse type, which I actually wanted to avoid.

I tried the following:

    typedef Eigen::SparseMatrix< double >  TpSpMatrix_csr;

    py::class_<TpSpMatrix_csr> csr_matrix_eigen(m, "csr_matrix_eigen");

    csr_matrix_eigen
    .def(py::init<>()
    , "Default constructor"
    )

    .def(py::init<TpSpMatrix_csr>()
    , "Init with csr matrix"
    , py::arg("A")
     )
    ;

    m.def("csr_test", []( TpSpMatrix_csr& A) { std::cout << "csr!"<< std::endl; }
        , "csr test"
        , py::arg("A").noconvert()
        );

After importing it into ipython I get the following:

In [2]: A = csr_matrix_eigen()

In [3]: csr_test(A)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-77568ef56cf5> in <module>
----> 1 csr_test(A)

TypeError: csr_test(): incompatible function arguments. The following argument types are supported:
    1. (A: scipy.sparse.csc_matrix[numpy.float64]) -> None

Invoked with: <eigen_test.csr_matrix_eigen object at 0x7f9e78265af0>

Is there a simpler way to achieve this compared to encapsulating the eigen sparse matrix in yet another class?
In short, I would like to expose the eigen sparse matrix without scipy.sparse being involved.


Solution

  • o.k., posting questions seems to help. Although I struggled with this problem for some time now, only after posting the question I found a solution, namely, I have to include a

    PYBIND11_MAKE_OPAQUE(TpSpMatrix_csr);
    
    

    at the top of my pybind interface file. I can now call my test function as desired. I hope that this may help someone else in a similar pronlem.