C++ with Pybind11#

Setup#

$ pip install pybind11
#include <pybind11/pybind11.h>
namespace py=pybind11
from setuptools import find_packages, setup
from pybind11.setup_helpers import build_ext, intree_extensions

ext_modules = intree_extensions(["path/to/mypkg/mypkg.cpp"])

setup(
    name="mypkg",
    version="0.0.0",
    cmdclass={"build_ext": build_ext},  # Uses latest C++ standard
    ext_modules=ext_modules,
)

Numpy#

For most usage of numpy, you’ll need to include the pybind11/numpy.h header.

Numpy to Pointer Arrays#

Since we’re dealing with pointers, this can be done without copying

// Adds two 1D double arrays.
void AddPtrArr(const double *x, const double *y, size_t size, double *z) {
  for (size_t i = 0; i < size; i++) {
    z[i] = x[i] + y[i];
  }
}

py::array_t<double> AddNumpy(const py::array_t<double> &x,
                              const py::array_t<double> &y) {
  // Assumes x and y are of same size and dimension of 1
  size_t s = x.size();
  auto result = py::array_t<double>(s);

  // We can pass in the input arrays' pointers to the first element
  // and pass the output array as a non-const pointer.
  AddPtrArr(x.data(), y.data(), x.size(), result.mutable_data());
  return result;
}

Numpy to Vectors#

Unfortunately C++ vector never was able to ingest pre-allocated arrays without copying.

// Adds two 1D double vectors.
vector<double> AddVector(const vector<double>& x, const vector<double>& y) {
  vector<double> z;
  for (size_t i = 0; i < x.size(); i++) {
    // Assumes x.size() == y.size()
    z.push_back(x[i] + y[i]);
  }
  return z;
}

py::array_t<double> AddNumpy(const py::array_t<double> &x,
                              const py::array_t<double> &y) {
  // Assumes x and y are of same size and dimension of 1
  size_t s = x.size();

  // Copy numpy array elements to new vectors
  vector<double> x_vec;
  x_vec.insert(x_vec.end(), &x[0], &x[x.size()])
  vector<double> y_vec;
  y_vec.insert(y_vec.end(), &y[0], &y[y.size()])

  vector<double> result = AddVector(x.data(), y.data());

  // Cast the vector to numpy
  py::array_t<double> result_numpy = py::cast(result)
  return result_numpy;
}