Content |
Array Storage and Dense Vectors
For dense vectors we follow the same concepts known from general matrices. We have three array storage schemes for realizing allocated, referenced and const referenced storage. Each of these storage classes can be used as template parameter for a dense vector class for the sake of providing a unified interface without runtime overhead.
Array Storage Schemes
FLENS defines three template classes for storing/referring an array:
-
Template Class Array
Constructors of Array allocate memory and the destructor deallocates it. The element type gets specified by a template parameter.
It is guaranteed that elements are stored contiguously in memory, i.e. without any gaps.
Example:
Array<double>
Storage scheme that allocates memory when instantiated. Elements of type double are stored contiguously.
Creating an instance of type Array involves dynamic memory allocation. So you do not want to create an instance inside a loop or a (frequently called) function.
-
Template Class ArrayView
An instance of type ArrayView is used to reference elements the are in memory separated by a constant stride. This can be a row/column of a general matrix or part of another array/vector.
Neither gets memory allocated on construction nor released on destruction. It is assumed that the referenced memory is managed by some other instance. For example by an instance of type FullStorage or Array.
An instance of type ArrayView just contains a pointer to raw data and some integers for length and element strides. Therefore creation of an instance is cheap. It just initializes a pointer and a few integer values of a struct/class.
-
Template Class ConstArrayView
Like ArrayView but it only provides the const methods of ArrayView.
For the moment we will not discuss further template parameters of the storage classes that allow to change the default index type (which is `long), the default index base (which is 1) and the memory allocator.
DenseVector: Dense Vector with Array Storage
The DenseVector class has only one templated paramter that defines the underlying storage scheme. So this again means that means a storage scheme gets a mathematical meaning by encapsulating it.
Examples:
DenseVector<Array<double> > |
A dense vector where memory gets allocated when instantiated and released at the end of its scope. |
DenseVector<Array<double> >::View |
A dense vector that references elements divided by a constant stride. In practise these can be elements from another vector but also from a row, column, diagonal, etc. of a general matrix. Creation/destruction is cheap. View is a publib typedef in DenseVector and in this case defined as DenseVector<ArrayView<double> > |
DenseVector<Array<double> >::ConstView |
Like DenseVector<..>::View just const. Attempts of calling a non-const method will trigger an static assertion failure. So an instance must be defined as const. ConstView is a public typedef in DenseVector and in this case defined as DenseVector<ConstArrayView<double> > |
Some Public Typedefs
IndexType |
Like its name suggests the type used for indexing. |
ElementType |
The element type. |
View, ConstView |
Types for referencing elements separated by a constant stride. |
NoView |
Vector type with memory allocation. If you want to copy vector parts instead of referencing use this type. |
EngineView, EngineConstView |
Storage schemes for referencing vectors. For DenseVector these are typedefs for ArrayView<..> and ConstArrayView<..>. |
Some Methods and operations for Matrix Manipulation
DenseVector(IndexType n) |
Constructor for a dense vector of length \(n\). |
IndexType length() const |
Returns the vector length. |
const ElementType & operator()(IndexType i) const |
Returns a reference to \(i\)-th element. |
ElementType & operator()(IndexType i) |
|
Initializer operator=(const ElementType &value) |
List initializer. Allows to initialize the vector with a comma separated list of values. If the list contains only a single value it is used to fill the vector. |
Like for matrices, by default indices start at 1, i.e. the index base is 1. Again, we are dealing with math entities not STL container. So usually that is what you want in numerical linear algebra. If you chance for some good reason the index base the following methods become useful:
IndexType firstIndex() const |
Return the first valid index. |
IndexType lastIndex() const |
Return the last valid index. |
Simple Example for using DenseVector
In a first example we show:
-
How to allocate a dense vector with array storage
-
How to explicitly initialize all elements with the list initializer.
-
How to fill the vector with a single value.
-
How to access/manipulate a particular matrix entry.
-
How to retrieve vector length and index ranges.
Example Code
#include <flens/flens.cxx>
using namespace flens;
using namespace std;
int
main()
{
typedef DenseVector<Array<double> > DDenseVector;
DDenseVector x(5);
x = 1, 2, 3, 4, 5;
cout << "x = " << x << endl;
cout << "Length of x: " << x.length() << endl;
cout << endl;
cout << "Indices: " << x.firstIndex() << ".." << x.lastIndex() << endl;
cout << endl;
x(2) = 42;
cout << "changed element: x(2) = " << x(2) << endl;
cout << endl;
cout << "x = " << x << endl;
x = 42;
cout << "x = " << x << endl;
return 0;
}
Comments on Example Code
We simply include everything of FLENS
#include <flens/flens.cxx>
Typedef for a dense vector with elements of type double.
Vector x gets dynamically allocated and then initialized.
x = 1, 2, 3, 4, 5;
Print the vector content using output streams:
We print some information about vector length and index ranges. You will see that by default in FLENS indices start at 1 (like in Fortran):
cout << endl;
cout << "Indices: " << x.firstIndex() << ".." << x.lastIndex() << endl;
cout << endl;
Also for element access (write) we provide a Fortran-Style interface:
The same for read access:
You also can fill the whole vector with a new value:
Compile and Run
$shell> cd flens/examples $shell> g++ -Wall -std=c++11 -I../.. tut01-page02-example1.cc $shell> ./a.out x = 1 2 3 4 5 Length of x: 5 Indices: 1..5 changed element: x(2) = 42 x = 1 42 3 4 5 x = 42 42 42 42 42
Simple Example for using DenseVector Views
In this example we show:
-
How to create a vector view that references every second element of another vector.
-
How to create vector views referencing complete rows/cols of a matrix.
-
How to create vector views referencing diagonals of a matrix.
Example Code
#include <flens/flens.cxx>
using namespace flens;
using namespace std;
int
main()
{
typedef GeMatrix<FullStorage<double> > DGeMatrix;
typedef DenseVector<Array<double> > DDenseVector;
Underscore<DDenseVector::IndexType> _;
DDenseVector x(5);
x = 1, 2, 3, 4, 5;
DGeMatrix A(4, 5);
A = 11, 12, 13, 14, 15,
21, 22, 23, 24, 25,
31, 32, 33, 34, 35,
41, 42, 43, 44, 45;
cout << "x = " << x << endl;
cout << "A = " << A << endl;
cout << endl;
DDenseVector::View y = x(_(1,2,5));
cout << "y = x(1:2:5) = " << y << endl;
cout << endl;
DDenseVector::View row = A(2,_);
cout << "row = A(2,:) = " << row << endl;
cout << endl;
DDenseVector::View rowPart = A(2,_(2,4));
cout << "rowPart = A(2,2:4) = " << rowPart << endl;
cout << endl;
DDenseVector::View col = A(_,3);
cout << "col = A(:,3) = " << col << endl;
cout << endl;
DDenseVector::View d0 = A.diag(0);
cout << "d0 = A.diag(0) = " << d0 << endl;
cout << endl;
DDenseVector::View d_1 = A.diag(-1);
cout << "d_1 = A.diag(-1) = " << d_1 << endl;
cout << endl;
DDenseVector::View d1 = A.diag(1);
cout << "d1 = A.diag(1) = " << d1 << endl;
cout << endl;
return 0;
}
Comments on Example Code
Allocate and initialize some vector ...
x = 1, 2, 3, 4, 5;
... and matrix.
A = 11, 12, 13, 14, 15,
21, 22, 23, 24, 25,
31, 32, 33, 34, 35,
41, 42, 43, 44, 45;
Print the vector and matrix
cout << "A = " << A << endl;
cout << endl;
Create a vector view that references every second element of x.
Create a vector view that references the second row of A
Create a vector view that references part of second row of A
Create a vector view that references the third column of A
Create a vector view that references the diagonal of A
Create a vector view that references the first sub-diagonal of A
Create a vector view that references the first super-diagonal of A
Compile and Run
$shell> cd flens/examples $shell> g++ -Wall -std=c++11 -I../.. tut01-page02-example2.cc $shell> ./a.out x = 1 2 3 4 5 A = 11 12 13 14 15 21 22 23 24 25 31 32 33 34 35 41 42 43 44 45 y = x(1:2:5) = 1 3 5 row = A(2,:) = 21 22 23 24 25 rowPart = A(2,2:4) = 22 23 24 col = A(:,3) = 13 23 33 43 d0 = A.diag(0) = 11 22 33 44 d_1 = A.diag(-1) = 21 32 43 d1 = A.diag(1) = 12 23 34 45