View on GitHub

Jules documentation

Documentation of the Jules library

Home Tutorial Modules Entities Files

What is an array?

In jules, an N-dimensional array consists of a collection of variables of same type that can be selected by N indices. The order of dimensionality N is a compile-time constant. The size of each dimension, although fixed after construction, is calculated at run-time.

In other words, an 1-dimensional array with 10 integer numbers is roughly equivalent to int array[10], while a 2-dimensional array with dimensions 5 and 2 to int array[5][2]. C arrays are contiguously stored in row-major order. jules arrays are also stored contiguously but in column-major order at the free store.

jules provides a series of convenient functions to manage arrays.

Using arrays

The simplest way to use all array facilities in jules is including the whole array module:

#include <jules/array/all.hpp>

This will expose the basic types jules::vector<T> for 1-dimensional arrays, jules::matrix<T> for 2-dimensional arrays, and jules::ndarray<N, T> for higher orders. If the type T is not specified, jules::numeric is used by default.

Constructors

There are several ways to create a vector, see the reference for more details.

// An empty vector.
auto a = jules::vector<>();

// A vector with 10 elements.
// If elements types are trivial, they are non-initialized.
// Otherwise, they are default initialized.
auto b = jules::vector<>(10u);

// A vector with 10 elements containing copies of 3.14.
auto c = jules::vector<>(3.14, 10u);

double values[] = {0.1, 0.2, 0.3, 0.4, 0.5};

// A vector from range of iterators.
auto d = jules::vector<>(std::begin(values), std::end(values));

// A vector from initializer_list.
auto e = jules::vector<>{0.1, 0.2, 0.3, 0.4, 0.5};

// A vector from an object that satifies the `Range` concept.
auto f = jules::vector<>(values);

// Copy and move constructor.
auto g = a;
auto h = std::move(b);

// A vector from other vector-like structures.
// See section "Lazy evaluation" for more information.
auto i = jules::vector<>(d + e);

The function jules::as_vector can be used to construct a vector whose elements type is inferred.

// A vector with elements whose type is inferred as double.
auto j = jules::as_vector(values);

// A vector with elements whose type is the common type of the arguments.
auto k = jules::as_vector(1, 2u, 3l);

For higher dimensional arrays, the constructors are basically the same. Consult the reference for a comprehensive list.

// An empty matrix.
auto a = jules::matrix<>();

// A matrix with 5 rows and 2 columns.
auto b = jules::matrix<>(5u, 2u);

// A matrix with 5 rows and 2 columns filled with elements 3.14.
auto c = jules::matrix<>(3.14, 5u, 2u);

double values[] = {0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9};

// A 3x3 matrix with elements from an iterator.
// The matrix is filled in column-major order.
auto d = jules::matrix<>(std::begin(values), 3u, 3u);

// A 3x3 matrix from a recursive initializer_list.
auto e = jules::matrix<>{
  {0.1, 0.4, 0.7},
  {0.2, 0.5, 0.8},
  {0.3, 0.6, 0.9},
};

// Copy and move constructor.
auto f = a;
auto g = std::move(b);

// A matrix from other matrix-like structures.
// See section "Lazy evaluation" for more information.
auto i = jules::matrix<>(d + e);

Element accessing

The most trivial array manipulation is accessing its elements. As traditional C-arrays, one can access jules arrays using operator[].

auto matrix = jules::matrix<>(0.0, 3u, 3u);
auto vector = jules::vector<>(0.0, 3u);

vector[0u] = 1.0;
// vector == {1.0, 0.0, 0.0}

matrix[1u][1u] = vector[0u];
// matrix == { {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 0.0} }

Alternatively (and potentially faster), one can use the operator() notation.

matrix(2u, 2u) = vector(0u);
// matrix == { {0.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0} }

Unlike C-arrays, one can assign entire sub-arrays if they have same dimensions.

matrix[0u] = vector;
// matrix == { {1.0, 0.0, 0.0}, {0.0, 1.0, 0.0}, {0.0, 0.0, 1.0} }