Basics

Tensor types

  • xarray<T>: tensor that can be reshaped to any number of dimensions.

  • xtensor<T, N>: tensor with a number of dimensions set to N at compile time.

  • xtensor_fixed<T, xshape<I, J, K>: tensor whose shape is fixed at compile time.

Note

Except if mentioned otherwise, the methods described below are available for the three kinds of containers, even if the examples show xarray usage only.

Initialization

Tensor with dynamic shape:

#include "xarray.hpp"

xt::xarray<double>::shape_type shape = {2, 3};
xt::xarray<double> a0(shape);
xt::xarray<double> a1(shape, 2.5);
xt::xarray<double> a2 = {{1., 2., 3.}, {4., 5., 6.}};
auto a3 = xt::xarray<double>::from_shape(shape);

Tensor with static number of dimensions:

#include "xtensor.hpp"

xt::xtensor<double, 2>::shape_type shape = {2, 3};
xt::xtensor<double, 2> a0(shape);
xt::xtensor<double, 2> a1(shape, 2.5);
xt::xtensor<double, 2> a2 = {{1., 2., 3.}, {4., 5., 6.}};
auto a3 = xt::xtensor<double, 2>::from_shape(shape);

Tensor with fixed shape:

#include "xfixed.hpp"

xt::xtensor_fixed<double, xt::xshape<2, 3>> = {{1., 2., 3.}, {4., 5., 6.}};

Output

#include "xarray.hpp"
#include "xfixed.hpp"
#include "xio.hpp"
#include "xtensor.hpp"

xt::xarray<double> a = {{1., 2.}, {3., 4.}};
std::cout << a << std::endl;

xt::xtensor<double, 2> b = {{1., 2.}, {3., 4.}};
std::cout << b << std::endl;

xt::xtensor_fixed<double, xt::xshape<2, 2>> c = {{1., 2.}, {3., 4.}};
std::cout << c << std::endl;

Shape - dimension - size

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
auto size = a.size();     // size = 6
auto dim = a.dimension(); // dim = 2
auto shape = a.shape();   // shape = {2, 3}
auto sh1 = a.shape(1);    // sh1 = 3

Reshape

The number of elements of an xarray must remain the same:

xt::xarray<double> a0 = {1., 2., 3., 4., 5., 6.};
a0.reshape({2, 3});
std::cout << a0 << std::endl;
// outputs {{1., 2., 3.}, {4., 5., 6. }}

For xtensor the number of elements and the number of dimensions must remain the same:

xt::xtensor<double, 2> a1 = {{1., 2.}, {3., 4.}, {5., 6.}};
a1.reshape({2, 3});
std::cout << a1 << std::endl;
// outputs {{1., 2., 3.}, {4., 5., 6. }}

One value in the shape can be -1. In this case, the value is inferred from the length of the underlying buffer and remaining dimensions:

xt::xarray<double> a0 = {1., 2., 3., 4., 5., 6.};
a0.reshape({2, -1});
std::cout << a0 << std::endl;
// outputs {{1., 2., 3.}, {4., 5., 6. }}

xt::xtensor<double, 2> a1 = {{1. 2.}, {3., 4.}, {5., 6.}};
a1.reshape({-1, 3});
std::cout << a1 << std::endl;
// outputs {{1., 2., 3.}, {4., 5., 6. }}

reshape is not defined for xtensor_fixed.

Resize

xt::xarray<double> a0 = {1., 2., 3, 4.};
a0.resize({2, 3});

When resizing an xtensor object, the number of dimensions must remain the same:

xt::xtensor<double, 2> a1 = {{1., 2.}, {3., 4.}};
a1.resize({2, 3});

resize is not defined for xtensor_fixed.

Warning

Contrary to STL containers like std::vector, resize do NOT preserve elements.

Element access

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
double d0 = a(0, 2);   // d0 is 6
double d1 = a(2);      // d1 is a(0, 2)
double d2 = a[{0, 2}]; // d2 is a(0, 2)

The same operators are used for writing values:

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
a(0, 2)   = 8.;
a(2)      = 8.;
a[{0, 2}] = 8.;

The at method is an access operator with bound checking:

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
double d0 = a.at(0, 3);   // throws
double d1 = a.at(3);      // throws

The periodic method is an access operator that applies periodicity to its arguments:

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
double d0 = a.periodic(2, -1); // d0 is 3

Fill

auto a = xt::xarray<double>::from_shape({2, 3});
a.fill(2.);
std::cout << a << std::endl;
// Outputs {{2., 2., 2.}, {2., 2., 2.}}

Iterators

xtensor containers provide iterators compatible with algorithms from the STL:

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
xt::xarray<double> b(a.shape());
std::transform(a.cbegin(), a.cend(), b.begin(), [](auto&& v) { return v + 1; });
std::cout << b << std::endl;
// Outputs {{2., 3., 4.}, {5., 6., 7.}}

Reverse iterators are also available:

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
xt::xarray<double> b(a.shape());
std::copy(a.crbegin(), a.crend(), b.begin());
std::cout << b << std::endl;
// Outputs {{6., 5., 4.}, {3., 2., 1.}}

Data buffer

The underlying 1D data buffer can be accessed with the data method:

xt::xarray<double> a = {{1., 2., 3.}, {4., 5., 6.}};
a.data()[4] = 8.;
std::cout << a << std::endl;
// Outputs {{1., 2., 3.}, {8., 5., 6.}}