Exchange data to and from cpp and numpy using buffer protocol
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <numeric> | |
#include <vector> | |
#include <pybind11/pybind11.h> | |
namespace py = pybind11; | |
/* | |
A very generic matrix class | |
*/ | |
class Matrix { | |
public: | |
Matrix(size_t rows, size_t cols) | |
: m_rows(rows), m_cols(cols) | |
{ | |
m_vec = std::vector<float>(rows * cols, 12.f); | |
} | |
float *data() { return &m_vec.front(); } | |
size_t rows() const { return m_rows; } | |
size_t cols() const { return m_cols; } | |
float sum() const | |
{ | |
return std::accumulate(m_vec.begin(), m_vec.end(), 0.f); | |
} | |
private: | |
size_t m_rows, m_cols; | |
std::vector<float> m_vec; | |
}; | |
void init_matrix(py::module& m) | |
{ | |
py::class_<Matrix> PyMatrix(m, "Matrix", py::buffer_protocol()); | |
PyMatrix.def(py::init<size_t,size_t>()); | |
// create matrix from numpy array using buffer protocol | |
PyMatrix.def(py::init([](py::buffer b) | |
{ | |
// request a buffer descriptor from python | |
py::buffer_info info = b.request(); | |
if (info.format != py::format_descriptor<float>::format()) | |
{ | |
throw std::runtime_error("Incompatible format: expected a float array!"); | |
} | |
if (info.ndim != 2) | |
{ | |
throw std::runtime_error("Incompatible buffer dimension!"); | |
} | |
std::unique_ptr<Matrix> M = std::make_unique<Matrix>(info.shape[0], info.shape[1]); | |
std::memcpy(M->data(), static_cast<float*>(info.ptr), info.shape[0] * info.shape[1] * sizeof(float)); | |
return M; | |
})); | |
// according to Python's buffer protocol specification | |
PyMatrix.def_buffer([](Matrix &m) -> py::buffer_info { | |
return py::buffer_info( | |
m.data(), /* Pointer to buffer */ | |
sizeof(float), /* Size of one scalar */ | |
py::format_descriptor<float>::format(), /* Python struct-style format descriptor */ | |
2, /* Number of dimensions */ | |
{ m.rows(), m.cols() }, /* Buffer dimensions */ | |
{ sizeof(float) * m.cols(), /* Strides (in bytes) for each index */ | |
sizeof(float) } | |
); | |
}); | |
PyMatrix.def("sum", &Matrix::sum); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
In python you can do the following to create a numpy array without copying from cpp Matrix. Please note for demonstration purposes the Matrix is initialized with 12.f