[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/QuantStack/quantstack-talks/master/QuantStack-CERN/src/index.html [Back]  [Original]

reveal.js
QuantStack [QuantStack]
QuantStack [QuantStack]

Going native: C++ as a first-class citizen of the Jupyter ecosystem

The team

Project Jupyter

  • Consistent set of tools to improve and unify scientific computing workflows,
  • An interface between metal and humans, metal and flesh.

From day 1, Jupyter was developed by scientists for scientists and educators

Interactive workflows

Programming languages are not only used to build complex systems, but also to explore and gain insight about

  • A computing resource
  • A data set
  • The outcome of a simulation

Interactive workflows:

  • Loading some data
  • Running some code
  • Showing a visualization
  • Running some more code...

The C++ programming language

  • Taylored for performances
  • With a massive community
  • Especially in HPC

(Outside of ROOT) We lack a good story for interative computing in C++

This hurts productivity of C++ software developers.

  • C++ is generally considered as a difficult programming language
  • Heterogeneous set of tools...
  • ... that don't always play well together
  • making scientific workflows hard to reproduce
xeus-cling [xeus-cling]

A C++ kernel for Jupyter based on

Live demo of Xeus-Cling

Jupyter interactive widgets

Another area where Jupyter shines is Jupyter interactive widgets

bqplot [bqplot]

Jupyter interactive widgets: thick front-end and thin back-end

widgets-arch [widgets-arch]
xwidgets [xwidgets]

Live demo of xwidgets

Next goal: implement C++ back-end for other widgets libraries

xleaflet [xleaflet]

Live demo of xleaflet

Voila

xtensor [xtensor]

The Lazy Tensor Algebra Expression System

Xtensor is a flexible expression system in which any data structure can be plugged, offering the most expressive API to the users.

What is xtensor?

  • A C++ template library for multi-dimensional array manipulation

    xtensor [xtensor]
    • Followings the idioms of the C++ STL

      (iterator pairs, clear value semantics)

    • But also an API similar to that of numpy

What is xtensor?

What is xtensor?

  • BLAS bindings to enable BLAS operations on xtensor expressions.

    xtensor-blas [xtensor-blas]
  • SIMD acceleration kernels.

    xsimd [xsimd]
  • All open-source (BSD License).

Ever heard of numpy ?

Python 3 - numpy

C++ 14 - xtensor


                                    np.array([[3, 4], [5, 6]])

                                    arr.reshape([3, 4])
                                

                                    xt::xarray<double>({{3, 4}, {5, 6}})
                                    xt::xtensor<double, 2>({{3, 4}, {5, 6}})
                                    arr.reshape({3, 4});
                                

                                    np.linspace(1.0, 10.0, 100)
                                    np.logspace(1.0, 10.0, 100)
                                    np.arange(3, 7)
                                    np.eye(4)
                                    np.zeros([3, 4])
                                    np.ones([3, 4])
                                

                                    xt::linspace<double>(1.0, 10.0, 100)
                                    xt::logspace<double>(1.0, 10.0, 100)
                                    xt::arange(3, 7)
                                    xt::eye(4)
                                    xt::zeros<double>({3, 4})
                                    xt::ones<double>({3, 4})
                                

Python 3 - numpy

C++ 14 - xtensor


                                    a[:, np.newaxis]
                                    a[:5, 1:]
                                    a[5:1:-1, :]
                                    np.broadcast(a, [4, 5, 7])
                                    np.vectorize(f)
                                    a[a > 5]
                                    a[[0, 1], [0, 0]]
                                

                                    xt::view(a, xt::all(), xt::newaxis())
                                    xt::view(a, xt::range(_, 5), xt::range(1, _))
                                    xt::view(a, xt::range(5, 1, -1), xt::all())
                                    xt::broadcast(a, {4, 5, 7})
                                    xt::vectorize(f)
                                    xt::filter(a, a > 5)
                                    xt::index_view(a, {{0, 0}, {1, 0}})
                                

                                    np.sum(a, axis=[0, 1])
                                    np.sum(a)
                                    np.prod(a, axis=1)
                                    np.prod(a)
                                    np.mean(a, axis=1)
                                    np.mean(a)
                                

                                    xt::sum(a, {0, 1})
                                    xt::sum(a)
                                    xt::prod(a, {1})
                                    xt::prod(a)
                                    xt::mean(a, {1})
                                    xt::mean(a)
                                

Python 3 - numpy

C++ 14 - xtensor


                                    np.where(a > 5, a, b)
                                    np.where(a > 5)
                                    np.any(a)
                                    np.all(a)
                                    np.logical_and(a, b)
                                    np.logical_or(a, b)
                                

                                    xt::where(a > 5, a, b)
                                    xt::where(a > 5)
                                    xt::any(a)
                                    xt::all(a)
                                    a && b
                                    a || b
                                

                                    np.absolute(a)
                                    np.exp(a)
                                    np.sqrt(a)
                                    np.cos(a)
                                    np.cosh(a)
                                    scipy.special.erf(a)
                                    np.isnan(a)
                                

                                    xt::abs(a)
                                    xt::exp(a)
                                    xt::sqrt(a)
                                    xt::cos(a)
                                    xt::cosh(a)
                                    xt::erf(a)
                                    xt::isnan(a)
                                

Python 3 - numpy

C++ 14 - xtensor


                                    np.random.seed(0)
                                    np.random.randn(10, 10)
                                    np.random.randint(10, 10)
                                    np.random.rand(3, 4)
                                

                                    xt::random::seed(0)
                                    xt::random::randn<double>({10, 10})
                                    xt::random::randint<int>({10, 10}})
                                    xt::random::rand<double>({3, 4}})
                                

                                    np.stack([a, b, c], axis=1)
                                    np.concatenate([a, b, c], axis=1)
                                

                                    xt::stack(xtuple(a, b, c), 1)
                                    xt::concatenate(xtuple(a, b, c), 1)
                                

Broadcasting


                                    xarray<int> a = {{1,  2,  3,  4},
                                                     {5,  6,  7,  8},
                                                     {9, 10, 11, 12}};
                                    xarray<int> b = { 1, 3, 5, 7};
                                

                                    xarray<int> res = a + b;
                                

Broadcasting


                                    xarray<double> a = {1., 2., 3., 4.};
                                

                                    auto res = xt::broadcast(a, {3, 4});
                                

                                    xarray<double> a, b, c;
                                    // ... initialization of a, b, and c ...
                                    auto res = broadcast(a + b * c, {3, 4});
                                

Iteration

Row-major iteration over the array for x in np.nditer(a)

                                for(auto it=a.begin(); it!=a.end(); ++it)
                                
Iterating over a with a prescribed broadcasting shape

                                a.begin({3, 4})
                                a.end({3, 4})
                                
Iterating over a in a column-major fashion

                                a.template begin<layout_type::column_major>()
                                a.template end<layout_type::column_major>()
                                
Iterating over a in a column-major fashion with a prescribed broadcasting shape

                                a.template begin<layout_type::column_major>({3, 4})
                                a.template end<layout_type::column_major>({3, 4})
                                

How do I try it without installing anything?

http://quantstack.net/xtensor

QuantStack website [QuantStack website]

Live demo

Language bindings with xtensor

Python bingings [Python bingings]
JuliaLang bindings [JuliaLang bindings]
R bindings [R bindings]
Python bingings [Python bingings]

A Simple Python extension (1/2)

C++: Using an algorithm from the STL on a numpy array


#include <numeric>                        // Standard library import for std::accumulate
#include "pybind11/pybind11.h"            // Pybind11 import to define Python bindings
#include "xtensor/xmath.hpp"              // xtensor import for the C++ universal functions
#define FORCE_IMPORT_ARRAY                // numpy C api loading
#include "xtensor-python/pyarray.hpp"     // Numpy bindings

double sum_of_sines(xt::pyarray<double>& m)
{
    auto sines = xt::sin(m);
    // sines does not actually hold any value, which are only computed upon access
    return std::accumulate(sines.begin(), sines.end(), 0.0);
}

PYBIND11_PLUGIN(xtensor_python_test)
{
    xt::import_numpy();
    pybind11::module m("xtensor_python_test", "Test module for xtensor python bindings");

    m.def("sum_of_sines", sum_of_sines,
        "Computes the sum of the sines of the values of the input array");

    return m.ptr();
}

Python bingings [Python bingings]

A simple Python extension (1/2)

Python: Using an algorithm from the STL on a numpy array


import numpy as np
import xtensor_python_test as xt

a = np.arange(15).reshape(3, 5)
xt.sum_of_sines(v)

Python bingings [Python bingings]

A simple Python extension (2/2)

C++: Create a universal function from a C++ scalar function


#include "pybind11/pybind11.h"
#define FORCE_IMPORT_ARRAY
#include "xtensor-python/pyvectorize.hpp"
#include <numeric>
#include <cmath>

namespace py = pybind11;

double scalar_func(double i, double j)
{
    return std::sin(i) - std::cos(j);
}

PYBIND11_PLUGIN(xtensor_python_test)
{
    xt::import_numpy();
    py::module m("xtensor_python_test", "Test module for xtensor python bindings");

    m.def("vectorized_func", xt::pyvectorize(scalar_func), "");

    return m.ptr();
}

Python bingings [Python bingings]

A simple Python extension (2/2)

Python: Create a numpy-style universal function from a C++ scalar function


import numpy as np
import xtensor_python_test as xt

x = np.arange(15).reshape(3, 5)
y = [1, 2, 3, 4, 5]
xt.vectorized_func(x, y)

Julia bingings [Julia bingings]

A Simple Julia extension (1/2)

C++: Using an algorithm from the STL on a Julia array


#include <numeric>                        // Standard library import for std::accumulate
#include "jlcxx/jlcxx.hpp                // CxxWrap import to define Julia bindings
#include "xtensor-julia/jltensor.hpp"     // Import the jltensor container definition
#include "xtensor/xmath.hpp"              // xtensor import for the C++ universal functions

double sum_of_sines(xt::jltensor<double, 2> m)
{
    auto sines = xt::sin(m);  // sines does not actually hold values.
    return std::accumulate(sines.cbegin(), sines.cend(), 0.0);
}

JULIA_CPP_MODULE_BEGIN(registry)
    jlcxx::Module mod = registry.create_module("xtensor_julia_test");
    mod.method("sum_of_sines", sum_of_sines);
JULIA_CPP_MODULE_END

Julia bingings [Julia bingings]

A simple Julia extension (1/2)

Julia: Using an algorithm from the STL on a Julia array


using xtensor_julia_test

arr = [[1.0 2.0]
       [3.0 4.0]]

sum_of_sines(arr)

Julia bingings [Julia bingings]

A simple Julia extension (2/2)

C++: Create a numpy-style universal function from a C++ scalar function


#include "jlcxx/jlcxx.hpp"
#include "xtensor-julia/jlvectorize.hpp"

double scalar_func(double i, double j)
{
    return std::sin(i) - std::cos(j);
}

JULIA_CPP_MODULE_BEGIN(registry)
    jlcxx::Module mod = registry.create_module("xtensor_julia_test");
    mod.method("vectorized_func", xt::jlvectorize(scalar_func));
JULIA_CPP_MODULE_END

Julia bingings [Julia bingings]

A simple Julia extension (2/2)

Julia: Create a numpy-style universal function from a C++ scalar function


using xtensor_julia_test

x = [[ 0.0  1.0  2.0  3.0  4.0]
     [ 5.0  6.0  7.0  8.0  9.0]
     [10.0 11.0 12.0 13.0 14.0]]
y = [1.0, 2.0, 3.0, 4.0, 5.0]
xt.vectorized_func(x, y)

R bingings [R bingings]

A Simple R extension

C++: Using an algorithm from the STL on a R array


// [[Rcpp::export]]
double sum_of_sines(xt::rarray<int> m)
{
    auto sines = xt::sin(m);  // sines does not actually hold values.
    return std::accumulate(sines.cbegin(), sines.cend(), 0.0);
}

R bingings [R bingings]

A simple R extension

R: Using an algorithm from the STL on a R array


library('xtensor_r_test')

arr <- array(c(c(1, 2), c(3, 4)), dim = c(2, 2)

xtensor_r_test::sum_of_sines(arr)

xtensor-cookiecutter [xtensor-cookiecutter]

Generate your packaged xtensor extension

  • With a few examples from the documentation
  • Unit-tests
  • HTML documentation
  • Packaging boilerplate (setup.py, build.jl)

Bindings with BLAS libraries

xtensor-blas [xtensor-blas]

BLAS-based implementation of numpy.linalg

  • ISO results with numpy.linalg is main goal
  • Seeking adoption by Python to C++ compilers (Pythran, Jet)
  • Works with any BLAS implementation (openblas, mkl, netlib)
  • See the numpy to xtensor cheat sheet

Continually benchmarking

We benchmark.
A lot!

benchmarks.png [benchmarks.png]
xframe [xframe]

Live demo of xframe

Resources:

GitHub

  • xeus: github.com/QuantStack/xeus/
  • xeus-cling: github.com/QuantStack/xeus-cling/
  • xproperty: github.com/QuantStack/xproperty/
  • xframe: github.com/QuantStack/xframe/
  • xtensor: github.com/QuantStack/xtensor/
  • xtensor-blas: github.com/QuantStack/xtensor-blas/
  • xtensor-python: github.com/QuantStack/xtensor-python/
  • xtensor-r: github.com/QuantStack/xtensor-r/
  • xtensor-julia: github.com/QuantStack/xtensor-julia/
  • xsimd: github.com/QuantStack/xsimd/
  • xtensor-fftw: github.com/egpbos/xtensor-fftw/
  • xwidgets: github.com/QuantStack/xwidgets/
  • xleaflet: github.com/QuantStack/xleaflet/
  • xplot: github.com/QuantStack/xplot/
  • xwebrtc: github.com/QuantStack/xwebrtc/

Resources:

Documentation

The End


Web Proxy Viewer  |  New URL  |  Original Page