18.4 Multiple indexes with vectors and matrices
Multiple indexes can be supplied to vectors and matrices as well as arrays of vectors and matrices.
Vectors
Vectors and row vectors behave exactly the same way as arrays with
multiple indexes. If v
is a vector, then v[3]
is a
scalar real value, whereas v[2:4]
is a vector of size 3
containing the elements v[2]
, v[3]
, and v[4]
.
The only subtlety with vectors is in inferring the return type when there are multiple indexes. For example, consider the following minimal example.
array[3] vector[5] v;
array[7] int idxs;
// ...
vector[7] u;
u = v[2, idxs];
array[7] real w;
w = v[idxs, 2];
The key is understanding that a single index always reduces
dimensionality, whereas a multiple index never does. The dimensions
with multiple indexes (and unindexed dimensions) determine the indexed
expression’s type. In the example above, because v
is an array
of vectors, v[2, idxs]
reduces the array dimension but doesn’t
reduce the vector dimension, so the result is a vector. In contrast,
v[idxs, 2]
does not reduce the array dimension, but does reduce
the vector dimension (to a scalar), so the result type for w
is
an array of reals. In both cases, the size of the multiple index
(here, 7) determines the size of the result.
Matrices
Matrices are a bit trickier because they have two dimensions, but the underlying principle of type inference is the same—multiple indexes leave dimensions in place, whereas single indexes reduce them. The following code shows how this works for multiple indexing of matrices.
matrix[5, 7] m;
// ...
row_vector[3] rv;
rv = m[4, 3:5]; // result is 1 x 3
// ...
vector[4] v;
v = m[2:5, 3]; // result is 3 x 1
// ...
matrix[3, 4] m2;
m2 = m[1:3, 2:5]; // result is 3 x 4
The key is realizing that any position with a multiple index or bounded index remains in play in the result, whereas any dimension with a single index is replaced with 1 in the resulting dimensions. Then the type of the result can be read off of the resulting dimensionality as indicated in the comments above.
Matrices with one multiple index
If matrices receive a single multiple index, the result is a matrix.
So if m
is a matrix, so is m[2:4]
. In contrast,
supplying a single index, m[3]
, produces a row vector result.
That is, m[3]
produces the same result as m[3, ]
or m[3, 1:cols(m)]
.
Arrays of vectors or matrices
With arrays of matrices, vectors, and row vectors, the basic access rules remain exactly the same: single indexes reduce dimensionality and multiple indexes redirect indexes. For example, consider the following example.
array[5, 7] matrix[3, 4] m;
// ...
array[2] matrix[3, 4] a;
a = m[1, 2:3]; // knock off first array dimension
a = m[3:4, 5]; // knock off second array dimension
In both assignments, the multiple index knocks off an array dimension,
but it’s different in both cases. In the first case, a[i] == m[1, i + 1]
, whereas in the second case, a[i] == m[i + 2, 5]
.
Continuing the previous example, consider the following.
// ...
vector[2] b;
b = a[1, 3, 2:3, 2];
Here, the two array dimensions are reduced as is the column dimension
of the matrix, leaving only a row dimension index, hence the result is
a vector. In this case, b[j] == a[1, 3, 1 + j, 2]
.
This last example illustrates an important point: if there is a
lower-bounded index, such as 2:3
, with lower bound 2, then the
lower bound minus one is added to the index, as seen in the 1 + j
expression above.
Continuing further, consider continuing with the following.
// ...
array[2] row_vector[3] c;
c = a[4:5, 3, 1, 2: ];
Here, the first array dimension is reduced, leaving a single array
dimension, and the row index of the matrix is reduced, leaving a row
vector. For indexing, the values are given by
c[i, j] == a[i + 3, 3, 1, j + 1]
Block, row, and column extraction for matrices
Matrix slicing can also be performed using the block
function. For
example,
matrix[20, 20] a = ...;
matrix[3, 2] b = block(a, 5, 9, 3, 2);
will set b
equal to the submatrix of a
starting at index [5, 9]
and extending 3 rows and 2 columns. Thus block(a, 5, 9, 3, 2)
is
equivalent to b[5:7, 9:10]
.
The sub_col
function extracts a slice of a column of a matrix as a
vector. For example,
matrix[10, 10] a = ...;
vector b = sub_col(a, 2, 3, 5);
will set b
equal to the vector a[2:6, 3]
, taking the element
starting at [2, 3], then extending for a total of 5 rows. The
function sub_row
works the same way for extracting a slice of a row
as a row vector. For example, sub_row(a, 2, 3, 5)
is equal to
the row vector a[2, 3:7]
, which also starts at position [2, 3] then
extends for a total of 5 columns.