![]() |
Subvectors provide views on a specific part of a dense or sparse vector. As such, subvectors act as a reference to a specific range within a vector. This reference is valid and can be used in every way any other dense or sparse vector can be used as long as the vector containing the subvector is not resized or entirely destroyed. The subvector also acts as an alias to the vector elements in the specified range: Changes made to the elements (e.g. modifying values, inserting or erasing elements) are immediately visible in the vector and changes made via the vector are immediately visible in the subvector. Blaze provides two subvector types: DenseSubvector and SparseSubvector.
The blaze::DenseSubvector template represents a view on a specific subvector of a dense vector primitive. It can be included via the header file
The type of the dense vector is specified two template parameters:
VT:
specifies the type of the dense vector primitive. DenseSubvector can be used with every dense vector primitive or view, but does not work with any vector expression type.AF:
the alignment flag specifies whether the subvector is aligned (blaze::aligned) or unaligned (blaze::unaligned). The default value is blaze::unaligned.
The blaze::SparseSubvector template represents a view on a specific subvector of a sparse vector primitive. It can be included via the header file
The type of the sparse vector is specified via two template parameters:
VT:
specifies the type of the sparse vector primitive. As in case of DenseSubvector, a SparseSubvector can be used with every sparse vector primitive or view, but does not work with any vector expression type.AF:
the alignment flag specifies whether the subvector is aligned (blaze::aligned) or unaligned (blaze::unaligned). The default value is blaze::unaligned.
A view on a dense or sparse subvector can be created very conveniently via the subvector()
function. This view can be treated as any other vector, i.e. it can be assigned to, it can be copied from, and it can be used in arithmetic operations. A subvector created from a row vector can be used as any other row vector, a subvector created from a column vector can be used as any other column vector. The view can also be used on both sides of an assignment: The subvector can either be used as an alias to grant write access to a specific subvector of a dense vector primitive on the left-hand side of an assignment or to grant read-access to a specific subvector of a vector primitive or expression on the right-hand side of an assignment. The following example demonstrates this in detail:
The subvector()
function can be used on any dense or sparse vector, including expressions, as demonstrated in the example. Note however that a DenseSubvector or SparseSubvector can only be instantiated with a dense or sparse vector primitive, respectively, i.e. with types that can be written, and not with an expression type.
A subvector view can be used like any other dense or sparse vector. For instance, the current number of elements can be obtained via the size()
function, the current capacity via the capacity()
function, and the number of non-zero elements via the nonZeros()
function. However, since subvectors are references to a specific range of a vector, several operations are not possible on views, such as resizing and swapping. The following example shows this by means of a dense subvector view:
The elements of a subvector can be directly accessed via the subscript operator:
The numbering of the subvector elements is
where N is the specified size of the subvector. Alternatively, the elements of a subvector can be traversed via iterators. Just as with vectors, in case of non-const subvectors, begin()
and end()
return an Iterator, which allows a manipulation of the non-zero values, in case of constant subvectors a ConstIterator is returned:
Inserting/accessing elements in a sparse subvector can be done by several alternative functions. The following example demonstrates all options:
Both dense and sparse subvectors can be used in all arithmetic operations that any other dense or sparse vector can be used in. The following example gives an impression of the use of dense subvectors within arithmetic operations. All operations (addition, subtraction, multiplication, scaling, ...) can be performed on all possible combinations of dense and sparse subvectors with fitting element types:
Usually subvectors can be defined anywhere within a vector. They may start at any position and may have an arbitrary size (only restricted by the size of the underlying vector). However, in contrast to vectors themselves, which are always properly aligned in memory and therefore can provide maximum performance, this means that subvectors in general have to be considered to be unaligned. This can be made explicit by the blaze::unaligned flag:
All of these calls to the subvector()
function are identical. Whether the alignment flag is explicitly specified or not, it always returns an unaligned subvector. Whereas this may provide full flexibility in the creation of subvectors, this might result in performance disadvantages in comparison to vector primitives (even in case the specified subvector could be aligned). Whereas vector primitives are guaranteed to be properly aligned and therefore provide maximum performance in all operations, a general view on a vector might not be properly aligned. This may cause a performance penalty on some platforms and/or for some operations.
However, it is also possible to create aligned subvectors. Aligned subvectors are identical to unaligned subvectors in all aspects, except that they may pose additional alignment restrictions and therefore have less flexibility during creation, but don't suffer from performance penalties and provide the same performance as the underlying vector. Aligned subvectors are created by explicitly specifying the blaze::aligned flag:
The alignment restrictions refer to system dependent address restrictions for the used element type and the available vectorization mode (SSE, AVX, ...). In order to be properly aligned the first element of the subvector must be aligned. The following source code gives some examples for a double precision dynamic vector, assuming that AVX is available, which packs 4 double
values into an intrinsic vector:
Note that the discussed alignment restrictions are only valid for aligned dense subvectors. In contrast, aligned sparse subvectors at this time don't pose any additional restrictions. Therefore aligned and unaligned sparse subvectors are truly fully identical. Still, in case the blaze::aligned flag is specified during setup, an aligned subvector is created:
It is also possible to create a subvector view on another subvector. In this context it is important to remember that the type returned by the subvector()
function is the same type as the type of the given subvector, not a nested subvector type, since the view on a subvector is just another view on the underlying vector:
Previous: Views Next: Submatrices