blaze::Subvector< VT, AF, TF, DF > Class Template Reference

View on a specific subvector of a dense or sparse vector.The Subvector class template represents a view on a specific subvector of a dense or sparse vector primitive. The type of the vector is specified via the first template parameter: More...

#include <BaseTemplate.h>

Detailed Description

template<typename VT, bool AF = unaligned, bool TF = IsRowVector<VT>::value, bool DF = IsDenseVector<VT>::value>
class blaze::Subvector< VT, AF, TF, DF >

View on a specific subvector of a dense or sparse vector.

The Subvector class template represents a view on a specific subvector of a dense or sparse vector primitive. The type of the vector is specified via the first template parameter:

template< typename VT, bool AF, bool TF, bool DF >
class Subvector;


Setup of Subvectors

A view on a dense or sparse subvector can be created very conveniently via the subvector() function:

DenseVectorType x;
// ... Resizing and initialization
// Create a dense subvector from index 8 with a size of 16 (i.e. in the range [8..23])
SparseVectorType x;
// ... Resizing and initialization
// Create a sparse subvector from index 5 with a size of 7 (i.e. in the range [5..11])

This view can be treated as any other dense or sparse vector, i.e. it can be assigned to, it can be copied from, and it can be used in arithmetic operations. 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 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:

DenseVectorType x;
SparseVectorType y;
DenseMatrixType A;
// ... Resizing and initialization
// Create a subvector from index 0 with a size of 10 (i.e. in the range [0..9])
// Setting the first ten elements of x to the 2nd row of matrix A
sv = row( A, 2UL );
// Setting the second ten elements of x to y
subvector( x, 10UL, 10UL ) = y;
// Setting the 3rd row of A to a subvector of x
row( A, 3UL ) = subvector( x, 3UL, 10UL );
// Setting x to a subvector of the result of the addition between y and the 1st row of A
x = subvector( y + row( A, 1UL ), 2UL, 5UL )


Element access

A subvector can be used like any other dense or sparse vector. For instance, the elements of the subvector can be directly accessed with the subscript operator.

VectorType v;
// ... Resizing and initialization
// Creating an 8-dimensional subvector, starting from index 4
// Setting the 1st element of the subvector, which corresponds to
// the element at index 5 in vector v
sv[1] = 2.0;

The numbering of the subvector elements is

\[\left(\begin{array}{*{5}{c}} 0 & 1 & 2 & \cdots & N-1 \\ \end{array}\right),\]

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:

using SubvectorType = blaze::Subvector<VectorType>;
VectorType v( 256UL );
// ... Resizing and initialization
// Creating a reference to a specific subvector of vector v
SubvectorType sv = subvector( v, 16UL, 64UL );
for( SubvectorType::Iterator it=sv.begin(); it!=sv.end(); ++it ) {
*it = ...; // OK: Write access to the dense subvector value.
... = *it; // OK: Read access to the dense subvector value.
}
for( SubvectorType::ConstIterator it=sv.begin(); it!=sv.end(); ++it ) {
*it = ...; // Compilation error: Assignment to the value via a ConstIterator is invalid.
... = *it; // OK: Read access to the dense subvector value.
}
using SubvectorType = blaze::Subvector<VectorType>;
VectorType v( 256UL );
// ... Resizing and initialization
// Creating a reference to a specific subvector of vector v
SubvectorType sv = subvector( v, 16UL, 64UL );
for( SubvectorType::Iterator it=sv.begin(); it!=sv.end(); ++it ) {
it->value() = ...; // OK: Write access to the value of the non-zero element.
... = it->value(); // OK: Read access to the value of the non-zero element.
it->index() = ...; // Compilation error: The index of a non-zero element cannot be changed.
... = it->index(); // OK: Read access to the index of the sparse element.
}
for( SubvectorType::ConstIterator it=sv.begin(); it!=sv.end(); ++it ) {
it->value() = ...; // Compilation error: Assignment to the value via a ConstIterator is invalid.
... = it->value(); // OK: Read access to the value of the non-zero element.
it->index() = ...; // Compilation error: The index of a non-zero element cannot be changed.
... = it->index(); // OK: Read access to the index of the sparse element.
}


Element Insertion

Inserting/accessing elements in a sparse subvector can be done by several alternative functions. The following example demonstrates all options:

VectorType v( 256UL ); // Non-initialized vector of size 256
using SubvectorType = blaze::Subvector<VectorType>;
SubvectorType sv = subvector( v, 10UL, 60UL ); // View on the range [10..69] of v
// The subscript operator provides access to all possible elements of the sparse subvector,
// including the zero elements. In case the subscript operator is used to access an element
// that is currently not stored in the sparse subvector, the element is inserted into the
// subvector.
sv[42] = 2.0;
// The second operation for inserting elements is the set() function. In case the element is
// not contained in the subvector it is inserted into the subvector, if it is already contained
// in the subvector its value is modified.
sv.set( 45UL, -1.2 );
// An alternative for inserting elements into the subvector is the insert() function. However,
// it inserts the element only in case the element is not already contained in the subvector.
sv.insert( 50UL, 3.7 );
// Just as in case of vectors, elements can also be inserted via the append() function. In
// case of subvectors, append() also requires that the appended element's index is strictly
// larger than the currently largest non-zero index of the subvector and that the subvector's
// capacity is large enough to hold the new element. Note however that due to the nature of
// a subvector, which may be an alias to the middle of a sparse vector, the append() function
// does not work as efficiently for a subvector as it does for a vector.
sv.reserve( 10UL );
sv.append( 51UL, -2.1 );


Common Operations

The current number of subvector 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 subvector are views on a specific subvector of a vector, several operations are not possible on views, such as resizing and swapping:

using SubvectorType = blaze::Subvector<VectorType>;
VectorType v( 42UL );
// ... Resizing and initialization
// Creating a view on the range [5..15] of vector v
SubvectorType sv = subvector( v, 5UL, 10UL );
sv.size(); // Returns the number of elements in the subvector
sv.capacity(); // Returns the capacity of the subvector
sv.nonZeros(); // Returns the number of non-zero elements contained in the subvector
sv.resize( 84UL ); // Compilation error: Cannot resize a subvector of a vector
SubvectorType sv2 = subvector( v, 15UL, 10UL );
swap( sv, sv2 ); // Compilation error: Swap operation not allowed


Arithmetic Operations

The following example gives an impression of the use of Subvector within arithmetic operations. All operations (addition, subtraction, multiplication, scaling, ...) can be performed on all possible combinations of dense and sparse vectors with fitting element types:

DenseVectorType d1, d2, d3;
SparseVectorType s1, s2;
// ... Resizing and initialization
DenseMatrixType A;
using SubvectorType = blaze::Subvector<DenseVectorType>;
SubvectorType sv( subvector( d1, 0UL, 10UL ) ); // View on the range [0..9] of vector d1
sv = d2; // Dense vector initialization of the range [0..9]
subvector( d1, 10UL, 10UL ) = s1; // Sparse vector initialization of the range [10..19]
d3 = sv + d2; // Dense vector/dense vector addition
s2 = s1 + subvector( d1, 10UL, 10UL ); // Sparse vector/dense vector addition
d2 = sv * subvector( d1, 20UL, 10UL ); // Component-wise vector multiplication
subvector( d1, 3UL, 4UL ) *= 2.0; // In-place scaling of the range [3..6]
d2 = subvector( d1, 7UL, 3UL ) * 2.0; // Scaling of the range [7..9]
d2 = 2.0 * subvector( d1, 7UL, 3UL ); // Scaling of the range [7..9]
subvector( d1, 0UL , 10UL ) += d2; // Addition assignment
subvector( d1, 10UL, 10UL ) -= s2; // Subtraction assignment
subvector( d1, 20UL, 10UL ) *= sv; // Multiplication assignment
double scalar = subvector( d1, 5UL, 10UL ) * trans( s1 ); // Scalar/dot/inner product between two vectors
A = trans( s1 ) * subvector( d1, 4UL, 16UL ); // Outer product between two vectors


Aligned Subvectors

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:

DenseVectorType x;
// ... Resizing and initialization
// Identical creations of an unaligned subvector in the range [8..23]
blaze::Subvector<DenseVectorType> sv2 = subvector<unaligned>( x, 8UL, 16UL );
blaze::Subvector<DenseVectorType,unaligned> sv4 = subvector<unaligned>( x, 8UL, 16UL );

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 restrictions (even in case the specified subvector could be aligned). 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:

// Creating an aligned subvector in the range [8..23]
blaze::Subvector<DenseVectorType,aligned> sv = subvector<aligned>( x, 8UL, 16UL );

The alignment restrictions refer to system dependent address restrictions for the used element type and the available vectorization mode (SSE, AVX, ...). The following source code gives some examples for a double precision dense vector, assuming that AVX is available, which packs 4 double values into a SIMD vector:

VectorType d( 17UL );
// ... Resizing and initialization
// OK: Starts at the beginning and the size is a multiple of 4
SubvectorType dsv1 = subvector<aligned>( d, 0UL, 12UL );
// OK: Start index and the size are both a multiple of 4
SubvectorType dsv2 = subvector<aligned>( d, 4UL, 8UL );
// OK: The start index is a multiple of 4 and the subvector includes the last element
SubvectorType dsv3 = subvector<aligned>( d, 8UL, 9UL );
// Error: Start index is not a multiple of 4
SubvectorType dsv4 = subvector<aligned>( d, 5UL, 8UL );
// Error: Size is not a multiple of 4 and the subvector does not include the last element
SubvectorType dsv5 = subvector<aligned>( d, 8UL, 5UL );

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:

SparseVectorType x;
// ... Resizing and initialization
// Creating an aligned subvector in the range [8..23]
blaze::SparseSubvector<SparseVectorType,aligned> sv = subvector<aligned>( x, 8UL, 16UL );


Subvectors on Subvectors

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, since the view on a subvector is just another view on the underlying vector:

using SubvectorType = blaze::Subvector<VectorType>;
VectorType d1;
// ... Resizing and initialization
// Creating a subvector view on the dense vector d1
SubvectorType sv1 = subvector( d1, 5UL, 10UL );
// Creating a subvector view on the dense subvector sv1
SubvectorType sv2 = subvector( sv1, 1UL, 5UL );

The documentation for this class was generated from the following file: