C++/Xeus Cling Environment
This notebook describes and creates the default C++/Xeus Cling environment in Nextjournal. Check out the showcase if you want to see what the environment contains. To see how it’s built, see setup.
Showcase
Imported from the Xeus Cling example notebook.
Output and error streams
std::cout
and std::cerr
are redirected to the notebook frontend.
#include <iostream>
std::cout << "some output" << std::endl;
std::cerr << "some error" << std::endl;
#include <stdexcept>
Commented out, kills a run-all.
//throw std::runtime_error("Unknown exception");
Omitting the ;
in the last statement of a cell results in an output being printed
int j = 5;
j
Interpreting the C++ programming language
cling
has a broad support of the features of C++. You can define functions, classes, templates, etc ...
Functions
double sqr(double a)
{
return a * a;
}
double a = 2.5;
double asqr = sqr(a);
asqr
Classes
class Foo
{
public:
virtual ~Foo() {}
virtual void print(double value) const
{
std::cout << "Foo value = " << value << std::endl;
}
};
Foo bar;
bar.print(1.2);
Polymorphism
class Bar : public Foo
{
public:
virtual ~Bar() {}
virtual void print(double value) const
{
std::cout << "Bar value = " << 2 * value << std::endl;
}
};
Foo* bar2 = new Bar;
bar2->print(1.2);
delete bar2;
Templates
#include <typeinfo>
template <class T>
class FooT
{
public:
explicit FooT(const T& t) : m_t(t) {}
void print() const
{
std::cout << typeid(T).name() << " m_t = " << m_t << std::endl;
}
private:
T m_t;
};
template <>
class FooT<int>
{
public:
explicit FooT(const int& t) : m_t(t) {}
void print() const
{
std::cout << "m_t = " << m_t << std::endl;
}
private:
int m_t;
};
FooT<double> foot1(1.2);
foot1.print();
FooT<int> foot2(4);
foot2.print();
C++11 / C++14 support
class Foo11
{
public:
Foo11() { std::cout << "Foo11 default constructor" << std::endl; }
Foo11(const Foo11&) { std::cout << "Foo11 copy constructor" << std::endl; }
Foo11(Foo11&&) { std::cout << "Foo11 move constructor" << std::endl; }
};
Foo11 f1;
Foo11 f2(f1);
Foo11 f3(std::move(f1));
#include <vector>
std::vector<int> v = { 1, 2, 3};
auto iter = ++v.begin();
v
*iter
... and also lambda, universal references, decltype
, etc ...
Documentation and completion
Documentation for types of the standard library is retrieved on cppreference.com.
The quick-help feature can also be enabled for user-defined types and third-party libraries. More documentation on this feature is available at https://xeus-cling.readthedocs.io/en/latest/inline_help.html.
?std::vector
Using the display_data mechanism
For a user-defined type T
, the rich rendering in the notebook and JupyterLab can be enabled by by implementing the function xeus::xjson mime_bundle_repr(const T& im)
, which returns the JSON mime bundle for that type.
More documentation on the rich display system of Jupyter and Xeus-cling is available at https://xeus-cling.readthedocs.io/en/latest/rich_display.html
Image example
#include <string>
#include <fstream>
#include "xtl/xbase64.hpp"
#include "xeus/xjson.hpp"
namespace im
{
struct image
{
inline image(const std::string& filename)
{
std::ifstream fin(filename, std::ios::binary);
m_buffer << fin.rdbuf();
}
std::stringstream m_buffer;
};
xeus::xjson mime_bundle_repr(const image& i)
{
auto bundle = xeus::xjson::object();
bundle["image/png"] = xtl::base64encode(i.m_buffer.str());
return bundle;
}
}
im::image marie(NJ__REF_);
marie
Audio example
#include <string>
#include <fstream>
#include "xtl/xbase64.hpp"
#include "xeus/xjson.hpp"
namespace au
{
struct audio
{
inline audio(const std::string& filename)
{
std::ifstream fin(filename, std::ios::binary);
m_buffer << fin.rdbuf();
}
std::stringstream m_buffer;
};
xeus::xjson mime_bundle_repr(const audio& a)
{
auto bundle = xeus::xjson::object();
bundle["text/html"] =
std::string("<audio controls=\"controls\"><source src=\"data:audio/wav;base64,")
+ xtl::base64encode(a.m_buffer.str()) +
"\" type=\"audio/wav\" /></audio>";
return bundle;
}
}
au::audio drums(NJ__REF_);
drums
Display
#include "xcpp/xdisplay.hpp"
xcpp::display(drums);
Update-display
#include <string>
#include "xcpp/xdisplay.hpp"
namespace ht
{
struct html
{
inline html(const std::string& content)
{
m_content = content;
}
std::string m_content;
};
xeus::xjson mime_bundle_repr(const html& a)
{
auto bundle = xeus::xjson::object();
bundle["text/html"] = a.m_content;
return bundle;
}
}
// A blue rectangle
ht::html rect(R"(
<div style='
width: 90px;
height: 50px;
line-height: 50px;
background-color: blue;
color: white;
text-align: center;'>
Original
</div>)");
xcpp::display(rect, "some_display_id");
// Update the rectangle to be red
rect.m_content = R"(
<div style='
width: 90px;
height: 50px;
line-height: 50px;
background-color: red;
color: white;
text-align: center;'>
Updated
</div>)";
xcpp::display(rect, "some_display_id", true);
Clear output
#include <chrono>
#include <iostream>
#include <thread>
#include "xcpp/xdisplay.hpp"
std::cout << "hello" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
xcpp::clear_output(); // will flicker when replacing "hello" with "goodbye"
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "goodbye" << std::endl;
std::cout << "hello" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
xcpp::clear_output(true); // prevents flickering
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "goodbye" << std::endl;
Magics
Magics are special commands for the kernel that are not part of the C++ language.
They are defined with the symbol %
for a line magic and %%
for a cell magic.
More documentation for magics is available at https://xeus-cling.readthedocs.io/en/latest/magics.html.
#include <algorithm>
#include <vector>
std::vector<double> to_shuffle = {1, 2, 3, 4};
Commented out, doesn't work.
// %timeit std::random_shuffle(to_shuffle.begin(), to_shuffle.end());
XTensor
GitHub repository: https://github.com/QuantStack/xtensor/
Online documentation: https://xtensor.readthedocs.io/
NumPy to xtensor cheat sheet: http://xtensor.readthedocs.io/en/latest/numpy.html
xtensor
is a C++ library for manipulating N-D arrays with an API very similar to that of numpy.
#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
#include "xtensor/xview.hpp"
xt::xarray<double> arr1
{{1.0, 2.0, 3.0},
{2.0, 5.0, 7.0},
{2.0, 5.0, 7.0}};
xt::xarray<double> arr2
{5.0, 6.0, 7.0};
xt::view(arr1, 1) + arr2
7. |
11. |
14. |
Together with the C++ Jupyter kernel, xtensor
offers a similar experience as NumPy
in the Python Jupyter kernel, including broadcasting and universal functions.
#include <iostream>
#include "xtensor/xarray.hpp"
#include "xtensor/xio.hpp"
xt::xarray<int> arr
{1, 2, 3, 4, 5, 6, 7, 8, 9};
arr.reshape({3, 3});
std::cout << arr;
#include "xtensor-blas/xlinalg.hpp"
xt::xtensor<double, 2> m = {{1.5, 0.5}, {0.7, 1.0}};
std::cout << "Matrix rank: " << std::endl << xt::linalg::matrix_rank(m) << std::endl;
std::cout << "Matrix inverse: " << std::endl << xt::linalg::inv(m) << std::endl;
std::cout << "Eigen values: " << std::endl << xt::linalg::eigvals(m) << std::endl;
xt::xarray<double> arg1 = xt::arange<double>(9);
xt::xarray<double> arg2 = xt::arange<double>(18);
arg1.reshape({3, 3});
arg2.reshape({2, 3, 3});
std::cout << xt::linalg::dot(arg1, arg2) << std::endl;
Setup
Install
The Xeus Cling Homepage really wants us to install this via conda
, so we'll base off the Minimal Python 3 environment. Make sure the default channels take priority—we want as little as possible from the conda-forge channel, to ensure smooth operation. May as well also install xtensor and its add-ons.
conda install -c defaults -c conda-forge \
xeus-cling cling xtensor xtensor-blas xtensor-io \
jupyter
conda clean -qtipy
ldconfig
Upgrade Jupyter components. Using dev on jupyter-core to address an issue with connection file permissions, remove when v4.6.2 comes out. —MPD, 17 Dec 2019.
pip install --upgrade jupyter-client \
git+https://github.com/jupyter/jupyter_core
Check.
du -hsx /
python -V
conda -V
jupyter kernelspec list
Test Kernel
int x = 1
x + 1
Appendix
DIR=share/jupyter/kernels/
[ -d ~/.ipython/kernels ] && find ~/.ipython/kernels -name kernel.json || true
[ -d ~/.local/${DIR} ] && find ~/.local/${DIR} -name kernel.json || true
[ -d /usr/${DIR} ] && find /usr/${DIR} -name kernel.json || true
[ -d /usr/local/${DIR} ] && find /usr/local/${DIR} -name kernel.json || true
[ -d /opt/conda/${DIR} ] && find /opt/conda/${DIR} -name kernel.json || true
find / -name kernel.json
This command starts the kernel, this is not meant to be run other than for debugging purposes
/opt/conda/bin/xcpp -f /connection_file.json -std=c++17
{
"stdin_port": 57557,
"ip": "127.0.0.1",
"control_port": 49615,
"hb_port": 42540,
"signature_scheme": "hmac-sha256",
"key": "",
"kernel_name": "",
"shell_port": 57555,
"transport": "tcp",
"iopub_port": 57556
}