Select Page

I recently came across (thanks to Nicolas D.) a great library called PyBind that originally was a condensed part of Boost dealing with Python interfacing.

It allows very easily to bind C++ and Python in many ways, relies heavily on meta-programmation (it is headers-only!). With it, it’s very simple to pass Numpy¬† arrays from Python to C++ and inversely dynamically create arrays in C++ and pass them to Python. You can install it with python-pip.

Here is a simple example of a C++ function accepting two Numpy arrays and returning the sum of both arrays in a Numpy array of the same shape.

For this dummy example, only 2-dimensionnal arrays are accepted but extending to more is trivial.
The C++ code, in a file called “example.cpp”, goes as follows (you can find all the code and instructions on my github page)

#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>

namespace py = pybind11;

py::array_t<double> add_arrays(py::array_t<double> input1, py::array_t<double> input2) {
   /* read input arrays buffer_info */
   py::buffer_info buf1 = input1.request(), buf2 = input2.request();
   if (buf1.size != buf2.size)
      throw std::runtime_error("Input shapes must match");

   /* allocate the output buffer */
   py::array_t<double> result = py::array_t<double>(buf1.size);
   py::buffer_info buf3 = result.request();
   double *ptr1 = (double *) buf1.ptr, *ptr2 = (double *) buf2.ptr, *ptr3 = (double *)buf3.ptr;
   size_t X = buf1.shape[0];
   size_t Y = buf1.shape[1];

   /* Add both arrays */
   for (size_t idx = 0; idx < X; idx++)
       for (size_t idy = 0; idy < Y; idy++)
           ptr3[idx*Y + idy] = ptr1[idx*Y+ idy] + ptr2[idx*Y+ idy];

   /* Reshape result to have same shape as input */

   return result;

PYBIND11_MODULE(example, m) {
   m.doc() = "Add two vectors using pybind11"; // optional module docstring
   m.def("add_arrays", &add_arrays, "Add two NumPy arrays");

To compile it I used

c++ -O3 -Wall -shared -std=c++11 -fPIC -I/usr/include/python2.7 -lpython2.7 `python -m pybind11 --includes` example.cpp -o example`python-config --extension-suffix`

And call it from Python with:

import numpy as np
import example 

a = np.zeros((10,3))
b = np.ones((10,3)) * 3
c = example.add_arrays(a, b)

print c

That’s is, there’s no tiring data passing hassle, as I had to do when doing similar stuff manually.

Thanks Remy for spotting the mistakes in the html code removing  <double> types.