Cast NumPy Array to/from Custom C++ Matrix-Class Using Pybind11

In the world of data science, it’s common to work with large datasets that require efficient processing. One way to achieve this is by leveraging the power of C++ and its high-performance libraries. However, integrating C++ code with Python, the lingua franca of data science, can be challenging. This is where pybind11 comes in handy. In this blog post, we’ll explore how to cast a NumPy array to and from a custom C++ Matrix-class using pybind11.

Cast NumPy Array to/from Custom C++ Matrix-Class Using Pybind11

In the world of data science , it’s common to work with large datasets that require efficient processing. One way to achieve this is by leveraging the power of C++ and its high-performance libraries. However, integrating C++ code with Python , the lingua franca of data science, can be challenging. This is where pybind11 comes in handy. In this blog post, we’ll explore how to cast a NumPy array to and from a custom C++ Matrix-class using pybind11 .

What is Pybind11?

Pybind11 is a lightweight header-only library that exposes C++ types in Python and vice versa. It’s a powerful tool that allows seamless interoperability between Python and C++. This means you can write high-performance code in C++ and make it available as a Python module, making it easier to integrate with your existing Python-based data science workflows.

Creating a Custom C++ Matrix-Class

Before we delve into casting, let’s first create a simple custom C++ Matrix-class. This class will represent a 2D matrix and will include basic operations such as getting and setting elements.

#include <vector>
class Matrix {
public:
    Matrix(size_t rows, size_t cols) : rows_(rows), cols_(cols) {
        data_.resize(rows * cols);
    double& operator()(size_t i, size_t j) {
        return data_[i * cols_ + j];
    const double& operator()(size_t i, size_t j) const {
        return data_[i * cols_ + j];
    size_t rows() const { return rows_; }
    size_t cols() const { return cols_; }
private:
    size_t rows_, cols_;
    std::vector<double> data_;

Binding the Matrix-Class with Pybind11

Now that we have our Matrix-class, we need to expose it to Python using pybind11 . We’ll create a new Python module named mymodule and add our Matrix class to it.

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
PYBIND11_MODULE(mymodule, m) {
    py::class_<Matrix>(m, "Matrix")
        .def(py::init<size_t, size_t>())
        .def("__getitem__", [](const Matrix &m, std::pair<size_t, size_t> idx) {
            return m(idx.first, idx.second);
        .def("__setitem__", [](Matrix &m, std::pair<size_t, size_t> idx, double val) {
            m(idx.first, idx.second) = val;

Casting NumPy Array to Matrix

To cast a NumPy array to our Matrix-class, we’ll add a new method to our Matrix class in the Python module. This method will take a NumPy array as input and return a Matrix object.

.def("from_numpy", [](py::array_t<double> input) {
    auto r = input.unchecked<2>();
    Matrix m(r.shape(0), r.shape(1));
    for (ssize_t i = 0; i < r.shape(0); ++i)
        for (ssize_t j = 0; j < r.shape(1); ++j)
            m(i, j) = r(i, j);
    return m;

Casting Matrix to NumPy Array

Similarly, to cast our Matrix-class back to a NumPy array, we’ll add another method to our Matrix class in the Python module. This method will take a Matrix object as input and return a NumPy array.

.def("to_numpy", [](const Matrix &m) {
    py::array_t<double> result({m.rows(), m.cols()});
    auto r = result.mutable_unchecked<2>();