In this notebook, we showcase the xtensor language bindings

This demo relies on

  • Min Ragan Kelley's "allthekernels" project which can be used to switch between several kernels in a single notebook
  • This also makes use of the xeus-cling [C++], and IRKernel [R] projects.

[C++] xtensor

We can use xtensor C++ library natively in the Jupyter notebook with the xeus-cling kernel


In [ ]:
%%file demo.cpp

#include <numeric>               // Standard library import for std::accumulate
#include <xtensor/xmath.hpp>     // xtensor import for the C++ universal functions

template <class E>
double sum_of_sines(E m)
{
    auto sines = xt::sin(m);
    // return xt::sum(sines)();
    return std::accumulate(sines.begin(), sines.end(), 0.0);
}

In [ ]:
>xcpp14

#include <iostream>
#include "demo.cpp"

std::cout << "HELLO C++ 14! " << sum_of_sines(xt::arange<double>(10000.0));

[Python] xtensor-python

We can expose the sum_of_sines to Python with pybind11 and xtensor-python.

#ifdef XPYTHON
#include "pybind11/pybind11.h"            // Pybind11 import to define Python bindings
#define FORCE_IMPORT_ARRAY
#include "xtensor-python/pyarray.hpp"     // Numpy bindings

PYBIND11_MODULE(xpython, m)
{
    xt::import_numpy();
    m.doc() = "Test module for xtensor python bindings";

    m.def("sum_of_sines", sum_of_sines<xt::pyarray<double, xt::layout_type::row_major>>,
                          "Sum the sines of the input values");
}
#endif

In [ ]:
%%bash
rm -f xpython.cpp

cp demo.cpp xpython.cpp

cat << EOF >> xpython.cpp
#include "pybind11/pybind11.h"            // Pybind11 import to define Python bindings
#define FORCE_IMPORT_ARRAY
#include "xtensor-python/pyarray.hpp"     // Numpy bindings

PYBIND11_MODULE(xpython, m)
{
    xt::import_numpy();
    m.doc() = "Test module for xtensor python bindings";

    m.def("sum_of_sines", sum_of_sines<xt::pyarray<double, xt::layout_type::row_major>>,
                          "Sum the sines of the input values");
}
EOF

In [ ]:
%%bash

export PYTHON_INCLUDES=`python3-config --includes`
export NUMPY_INCLUDES=`python -c "import numpy; print(numpy.get_include())"`

$CXX -w -shared -fPIC \
     -I${CONDA_PREFIX}/include \
     -L${CONDA_PREFIX}/lib/ \
     -I${NUMPY_INCLUDES} \
     ${PYTHON_INCLUDES} \
     xpython.cpp -o xpython.so

In [ ]:
>python3
import numpy as np
from xpython import sum_of_sines

x = np.arange(10000.0)
print("NumPy  : ", np.sum(np.sin(x)))
print("xtensor: ", sum_of_sines(x))

[R] xtensor-r

We can expose the sum_of_sines to R with Rcpp and xtensor-r.

#include <xtensor-r/rarray.hpp>       // R bindings
#include <Rcpp.h>

using namespace Rcpp;

// [[Rcpp::plugins(cpp14)]]
// [[Rcpp::export]]
double sum_of_sines(const xt::rarray<double>& e)
{
    return sum_of_sines_impl(e);
}
#endif

In [ ]:
%%bash
rm -f xr.cpp
cp demo.cpp xr.cpp

cat << EOF >> xr.cpp
#include <xtensor-r/rarray.hpp>       // R bindings
#include <Rcpp.h>
using namespace Rcpp;

// [[Rcpp::plugins(cpp14)]]
// [[Rcpp::export]]
double rsum_of_sines(const xt::rarray<double>& e) {
    return sum_of_sines(e);
}
EOF

In [ ]:
>ir
conda_prefix <- Sys.getenv("CONDA_PREFIX")
Sys.setenv(PKG_CXXFLAGS=paste("-I", conda_prefix, "/include/", sep=""))
Rcpp::sourceCpp("xr.cpp");

arr <- seq(0., 10000.0 - 1.0, 1.0)
rsum_of_sines(arr)