Multi-dimensional array

Back to Data structures

An array is a function from a rectangular subset of onto an arbitrary set.

Practice

Pastel implements the Array class template for storing and manipulating homogeneous-type multi-dimensional arrays with dynamic extents. Array is a class template defined as:

template <typename Type, integer N = 2>
class Array;

The first template parameter Type is the type of the elements that are stored in the array. The second template parameter N is the dimensionality of the array. For example, N == 1 corresponds roughly to an std::vector, while N == 2 corresponds to a matrix of values. N == Dynamic can be used for an array whose dimensionality can be set at run-time.

Element access

By coordinates

The elements of an Array are accessed using n-dimensional Vectors with integer elements. For example:

// Create a 2d-array of extents (3, 3) and fill with zeros.
Array<float> a(Vector2i(3, 3), 0);
// Set the element (0, 2) to 2.
a(Vector2i(0, 2)) = 2;
// Alternatively for 2d-arrays the same can be achieved by:
b(0, 2) = 2;

By sub-arrays

It is possible to consider a sub-array of an array and read from and write to it. This is done by specifying an integer rectangle on the element coordinates by its minimum and maximum coordinates. For example:

// Create a 2d-array of size 100 x 100, filled with zeros.
Array<float> b(Vector2i(100, 100), 0);

// Consider the lower-left corner of 'b'.
SubArray<float> bSub = b(Vector2i(0, 0), Vector2i(50, 50));
// Fill the lower-left corner with ones.
std::fill(bSub.begin(), bSub.end(), 1);

In the following we select from the lower-left corner of ‘b’ every 2nd in the horizontal direction, and every 3rd in the vertical direction, and fill that sub-array with twos.

// Consider the lower-left corner of 'b' with sparseness.
SubArray<float> sbSub = b(Vector2i(0, 0), Vector2i(50, 50), Vector2i(2, 3));
// Fill the lower-left corner sparsily with twos.
std::fill(sbSub.begin(), sbSub.end(), 2);

Special functions for low dimensions

The ‘Array’ supports some special member functions which might be more convenient to use when the dimension is 3 or lower and genericy is not needed.

Interpretation as a sequence

While Array is a multi-dimensional data structure, it is still sometimes useful to traverse its elements sequentially. The elements in this sequence can be accessed through an iterator interface, or alternatively by specifying an index. Specifically, this allows using the Standard Library algorithms on the elements. The ordering of the sequence depends on the storage order.

Storage order

The elements of an Array are stored sequentially in memory by a lexicographical ordering of their coordinates. There are two ways to order the elements: either row-major, or column-major.

In row-major ordering the elements are listed in lexicographical order of their coordinates, where the first coordinate is dominant, and for k > 1, the (k - 1):th coordinate is more dominant than the k:th coordinate (in 2d, column-by-column, row-by-row).

In column-major ordering the elements are listed in lexicographical order of their coordinates, where the last coordinate is dominant, and for k < n, the (k + 1):th coordinate is more dominant than the k:th coordinate (in 2d, row-by-row, column-by-column).

Aliasing

An Array can reuse an existing memory region for its elements. This is called aliasing. In this case Array does not release the aliased memory region when it is no longer needed. Aliasing is especially useful when interfacing with another software: then the data need not be copied just to be able manipulate it through an Array class. When aliasing, it is important to keep in mind the storage ordering of Pastel and the storage ordering of the aliased memory region. For example, Matlab uses column-major storage order.

Resizing

Resizing changes the extents of an Array. In this process, those coordinates which are inside the new extents preserve their value, and the possible newly created elements are assigned a given value. For example, a 2-dimensional integer array with extents (3, 4)

[1,   2,  3]
[4,   5,  6]
[7,   8,  9]
[10, 11, 12]

can be resized into a 2-dimensional array with extents (6, 2) and assigning new elements zero value:

[1, 2, 3, 0, 0, 0]
[4, 5, 6, 0, 0, 0]

Reshaping

Reshaping is the reinterpretation of the elements currently in the array as an array with different extents. Reshaping requires that the old extents and the new extents cover the same amount of elements. No memory is allocated or deallocated in this process. For example, a 2-dimensional integer array with extents (3, 4)

[1,   2,  3]
[4,   5,  6]
[7,   8,  9]
[10, 11, 12]

can be reshaped into a 2-dimensional array with extents (6, 2):

[1, 2, 3,  4,  5,  6]
[7, 8, 9, 10, 11, 12]

The result of the reshaping depends on the storage order. In the example above we assumed row-major storage order. If the storage order were column-major instead, then the result would be

[1,  7, 2,  8, 3,  9]
[4, 10, 5, 11, 6, 12]

Files

Array class

An n-dimensional array

Array module

Cursor for Array

SubArray class

Testing for Array