Indices

Definition

There are two types of indices: array indices and flat indices. Consider this example (stored in row-major):

#include <xtensor/xtensor.hpp>
#include <xtensor/xarray.hpp>
#include <xtensor/xio.hpp>

int main()
{
    xt::xarray<size_t> a = xt::arange<size_t>(3 * 4);

    a.reshape({3,4});

    std::cout << a << std::endl;
}

Which prints

{{ 0,  1,  2,  3},
 { 4,  5,  6,  7},
 { 8,  9, 10, 11}}

The array index {1, 2} corresponds to the flat index 6.

Operators: array index

An array index can be specified to an operators by a sequence of numbers. To this end the following operators are at your disposal:

operator()(args...)

Returns a (constant) reference to the element, specified by an array index given by a number of unsigned integers.

Note

If the number of indices is less that the dimension of the array, the indices are pre-padded with zeros until the dimension is matched (example: a(2) == a(0, 2) == 2).

at(args...)

  • Example: a.at(1, 2) == 6.

  • See also: xt::xcontainer::at().

Same as operator(): Returns a (constant) reference to the element, specified by an array index given by a number of unsigned integers.

unchecked(args...)

Returns a (constant) reference to the element, specified by an array index given by a number of unsigned integers. Different than operator() there are no bounds checks (even when assertions) are turned on, and the number of indices is assumed to match the dimension of the array. unchecked is thus aimed at performance.

Note

If you assume responsibility for bounds-checking, this operator can be used to virtually post-pad zeros if you specify less indices than the rank of the array. Example: a.unchecked(1) == a(1, 0).

periodic(args...)

  • Example: a.periodic(-1, -2) == 7.

  • See also: xt::xcontainer::periodic().

Returns a (constant) reference to the element, specified by an array index given by a number of signed integers. Negative and ‘overflowing’ indices are changed by assuming periodicity along that axis. For example, for the first axis: -1 -> a.shape(0) - 1 = 2, likewise for example 3 -> 3 - a.shape(0) = 0. Of course this comes as the cost of some extra complexity.

in_bounds(args...)

  • Example: a.in_bounds(1, 2) == true.

  • See also: xt::xcontainer::in_bounds().

Check if the array index is ‘in bounds’, return false otherwise.

operator[]({...})

  • Example: a[{1, 2}] == 6.

  • See also: xt::xcontainer::operator[]().

Returns a (constant) reference to the element, specified by an array index given by a list of unsigned integers.

Operators: flat index

flat(i)

  • Example: a.flat(6) == 6.

  • See also: xt::xcontainer::flat().

Returns a (constant) reference to the element specified by a flat index, given an unsigned integer.

Note

If the layout would not have been the default row major, but column major, then a.flat(6) == 2.

Note

In many cases a.flat(i) == a.data()[i].

Array indices

Functions like xt::argwhere(a < 5) return a std::vector of array indices. Using the same matrix as above, we can do

int main()
{
    xt::xarray<size_t> a = xt::arange<size_t>(3 * 4);

    a.reshape({3,4});

    auto idx = xt::from_indices(xt::argwhere(a >= 6));

    std::cout << idx << std::endl;
}

which prints

{{1, 2},
 {1, 3},
 {2, 0},
 {2, 1},
 {2, 2},
 {2, 3}}

To print the std::vector, it is converted to a xt::xtensor<size_t, 2> array, which is done using xt::from_indices.

From array indices to flat indices

To convert the array indices to a xt::xtensor<size_t, 1> of flat indices, xt::ravel_indices can be used. For the same example:

#include <xtensor/xtensor.hpp>
#include <xtensor/xarray.hpp>
#include <xtensor/xio.hpp>

int main()
{
    xt::xarray<size_t> a = xt::arange<size_t>(3 * 4);

    a.reshape({3,4});

    auto idx = xt::ravel_indices(xt::argwhere(a >= 6), a.shape());

    std::cout << idx << std::endl;
}

which prints

{ 6,  7,  8,  9, 10, 11}

Note

To convert to a std::vector use

auto idx = xt::ravel_indices<xt::ravel_vector_tag>(xt::argwhere(a >= 6), a.shape());

1-D arrays: array indices == flat indices

For 1-D arrays the array indices and flat indices coincide. One can use the generic functions xt::flatten_indices to get a xt::xtensor<size_t, 1> of (array/flat) indices. For example:

#include <xtensor/xtensor.hpp>
#include <xtensor/xview.hpp>
#include <xtensor/xio.hpp>

int main()
{
    xt::xtensor<size_t, 1> a = xt::arange<size_t>(16);

    auto idx = xt::flatten_indices(xt::argwhere(a >= 6));

    std::cout << idx << std::endl;

    std::cout << xt::view(a, xt::keep(idx)) << std::endl;
}

which prints the indices and the selection (which are in this case identical):

{ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15}
{ 6,  7,  8,  9, 10, 11, 12, 13, 14, 15}

From flat indices to array indices

To convert flat indices to array_indices the function xt::unravel_indices can be used. For example

#include <xtensor/xarray.hpp>
#include <xtensor/xtensor.hpp>
#include <xtensor/xstrides.hpp>
#include <xtensor/xio.hpp>

int main()
{
    xt::xarray<size_t> a = xt::arange<size_t>(3 * 4);

    a.reshape({3,4});

    auto flat_indices = xt::ravel_indices(xt::argwhere(a >= 6), a.shape());

    auto array_indices = xt::from_indices(xt::unravel_indices(flat_indices, a.shape()));

    std::cout << "flat_indices = " << std::endl << flat_indices << std::endl;
    std::cout << "array_indices = " << std::endl << array_indices << std::endl;
}

which prints

flat_indices =
{ 6,  7,  8,  9, 10, 11}
array_indices =
{{1, 2},
 {1, 3},
 {2, 0},
 {2, 1},
 {2, 2},
 {2, 3}}

Notice that once again the function xt::from_indices has been used to convert a std::vector of indices to a xt::xtensor array for printing.