Cast NumPy Array to/from 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>();