![]() |
Matrices are just as easy and intuitive to create as vectors. Still, there are a few rules to be aware of:
The DynamicMatrix and CompressedMatrix classes offer a constructor that allows to immediately give the matrices a specific number of rows and columns:
Note that dense matrices (in this case DynamicMatrix) immediately allocate enough capacity for all matrix elements. Sparse matrices on the other hand (in this example CompressedMatrix) merely acquire the size, but don't necessarily allocate memory.
All dense matrix classes offer a constructor for a direct, homogeneous initialization of all matrix elements. In contrast, for sparse matrices the predicted number of non-zero elements can be specified.
The StaticMatrix class offers a special initialization constructor. For StaticMatrix of up to 10 elements the vector elements can be individually specified in the constructor:
All dense and sparse matrices can be created as a copy of another dense or sparse matrix.
Note that it is not possible to create a StaticMatrix as a copy of a matrix with a different number of rows and/or columns:
There are several types of assignment to dense and sparse matrices: Homogeneous Assignment, Array Assignment, Copy Assignment, and Compound Assignment.
It is possible to assign the same value to all elements of a dense matrix. All dense matrix classes provide an according assignment operator:
Dense matrices can also be assigned a static array:
Note that due to the different storage order, the matrix M1 is initialized differently than matrix M2:
All kinds of matrices can be assigned to each other. The only restriction is that since a StaticMatrix cannot change its size, the assigned matrix must match both in the number of rows and in the number of columns.
Compound assignment is also available for matrices: addition assignment, subtraction assignment, and multiplication assignment. In contrast to plain assignment, however, the number of rows and columns of the two operands have to match according to the arithmetic operation.
Note that the multiplication assignment potentially changes the number of columns of the target matrix:
Since a StaticMatrix cannot change its size, only a quadratic StaticMatrix can be used in a multiplication assignment with other quadratic matrices of the same dimensions.
The current number of rows of a matrix can be acquired via the rows()
function:
The current number of columns of a matrix can be acquired via the columns()
function:
The capacity()
function returns the internal capacity of a DynamicMatrix or CompressedMatrix. Note that the capacity of a matrix doesn't have to be equal to the size of a matrix. In case of a dense matrix the capacity will always be greater or equal than the total number of elements of the matrix. In case of a sparse matrix, the capacity will usually be much less than the total number of elements.
For both dense and sparse matrices the current number of non-zero elements can be queried via the nonZeros()
function. In case of matrices there are two flavors of the nonZeros() function: One returns the total number of non-zero elements in the matrix, the second returns the number of non-zero elements in a specific row (in case of a row-major matrix) or column (in case of a column-major matrix). Sparse matrices directly return their number of non-zero elements, dense matrices traverse their elements and count the number of non-zero elements.
The dimensions of a StaticMatrix are fixed at compile time by the second and third template parameter. In contrast, the number or rows and/or columns of DynamicMatrix and CompressedMatrix can be changed at runtime:
When the internal capacity of a matrix is no longer sufficient, the allocation of a larger junk of memory is triggered. In order to avoid frequent reallocations, the reserve()
function can be used up front to set the internal capacity:
Additionally it is possible to reserve memory in a specific row (for a row-major matrix) or column (for a column-major matrix):
Note that resizing a matrix invalidates all existing views (see View Types) on the matrix:
The easiest way to access a specific dense or sparse matrix element is via the function call operator. The indices to access a matrix are zero-based:
Since dense matrices allocate enough memory for all contained elements, using the function call operator on a dense matrix directly returns a reference to the accessed value. In case of a sparse matrix, if the accessed value is currently not contained in the matrix, the value is inserted into the matrix prior to returning a reference to the value, which can be much more expensive than the direct access to a dense matrix. Consider the following example:
Although the compressed matrix is only used for read access within the for loop, using the function call operator temporarily inserts 16 non-zero elements into the matrix. Therefore, all matrices (sparse as well as dense) offer an alternate way via the begin()
and end()
functions to traverse all contained elements by iterator. Note that it is not possible to traverse all elements of the matrix, but that it is only possible to traverse elements in a row/column-wise fashion. In case of a non-const matrix, begin()
and end()
return an Iterator, which allows a manipulation of the non-zero value, in case of a constant matrix a ConstIterator is returned:
Whereas a dense matrix always provides enough capacity to store all matrix elements, a sparse matrix only stores the non-zero elements. Therefore it is necessary to explicitly add elements to the matrix. The first possibility to add elements to a sparse matrix is the function call operator:
In case the element at the given position is not yet contained in the sparse matrix, it is automatically inserted. Otherwise the old value is replaced by the new value 2. The operator returns a reference to the sparse vector element.
However, insertion of elements can be better controlled via the insert()
function. In contrast to the function call operator it emits an exception in case the element is already contained in the matrix. In order to check for this case, the find()
function can be used:
Although the insert()
function is very flexible, due to performance reasons it is not suited for the setup of large sparse matrices. A very efficient, yet also very low-level way to fill a sparse matrix is the append()
function. It requires the sparse matrix to provide enough capacity to insert a new element in the specified row. Additionally, the index of the new element must be larger than the index of the previous element in the same row. Violating these conditions results in undefined behavior!
The most efficient way to fill a sparse matrix with elements, however, is a combination of reserve()
, append()
, and the finalize()
function:
In order to reset all elements of a dense or sparse matrix, the reset()
function can be used. The number of rows and columns of the matrix are preserved:
In order to return a matrix to its default state (i.e. the state of a default constructed matrix), the clear()
function can be used:
Matrices can be transposed via the trans()
function. Row-major matrices are transposed into a column-major matrix and vice versa:
Via the
it is possible to completely swap the contents of two matrices of the same type:swap()
function