Content

Dense Vectors

Dense vectors have their elements stored linearly in memory separated from each other by a constant stride. If you create a dense vector that allocates its own memory then its stride will equal one. Strides different from one naturally arise when dealing with vector views. Vector views can reference vector slices or rows/columns of matrices.

First Steps

We start with the typical task: setting up a vector, initializing it, manipulating it and printing it.

Example Code

#include <flens/flens.cxx>
#include <iostream>

using namespace flens;
using namespace std;

int
main()
{

    typedef DenseVector<Array<double> >   DenseVector;
    typedef DenseVector::IndexType        IndexType;

    DenseVector x(4);
    x = 1234;

    cout << "x.range() = " << x.range() << endl;
    cout << "x.length() = " << x.length() << endl;

    cout << "x = " << x << endl;

    for (IndexType i=x.firstIndex(); i<=x.lastIndex(); ++i) {
        x(i) = i*i;
    }

    const Underscore<IndexType> _;

    DenseVector::View y = x(_(2,4));
    y = 666;

    DenseVector::NoView z = x(_(1,2));
    z = 42;

    cout << "x = " << x << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;
}

Comments on Example Code

The storage scheme for DenseVector is Array, ArrayView or ConstArrayView. We setup a typedef for a “regular” dense vector that allocates its own memory.

    typedef DenseVector<Array<double> >   DenseVector;
    typedef DenseVector::IndexType        IndexType;

We define a dense vector of length 4 and initialize it.

    DenseVector x(4);
    x = 1234;

We retrieve some information like index range and vector length. You will see that the default index base is One.

    cout << "x.range() = " << x.range() << endl;
    cout << "x.length() = " << x.length() << endl;

We print the vector.

    cout << "x = " << x << endl;

We iterate through the vector and reset its elements (such that \(x_i = i^2\)).

    for (IndexType i=x.firstIndex(); i<=x.lastIndex(); ++i) {
        x(i) = i*i;
    }

For selecting vector parts we define a range operator

    const Underscore<IndexType> _;

We create a vector view y that references a part of x.

    DenseVector::View y = x(_(2,4));
    y = 666;

Here we create a new vector z that allocates its own memory and initializes it with a copy of a part of x. So z is no vector view.

    DenseVector::NoView z = x(_(1,2));
    z = 42;

Compile and Run

$shell> cd flens/examples                                                     
$shell> clang++ -Wall -std=c++0x -I../.. tut01-page04-example01.cc            
$shell> ./a.out                                                               
x.range() = [1,4]
x.length() = 4
x = 
          1            2            3            4 
x = 
          1          666          666          666 
y = 
        666          666          666 
z = 
         42           42 

Vectors Referencing Matrix Rows, Columns and Diagonals

Referencing rows, columns or diagonals of a matrix is a common task in numerical algorithms. So here we show how to do this for general matrices where the corresponding vector views are dense vectors.

Example Code

#include <flens/flens.cxx>
#include <iostream>

using namespace flens;
using namespace std;

int
main()
{
    typedef GeMatrix<FullStorage<double, ColMajor> >    GeMatrix;
    typedef DenseVector<Array<double> >                 DenseVector;
    typedef DenseVector::IndexType                      IndexType;

    const Underscore<IndexType> _;

    GeMatrix  A(45);
    A =  1,  2,  3,  4,  5,
         6,  7,  8,  910,
        1112131415,
        1617181920;

    DenseVector::View y = A(2,_);
    y = 666;

    DenseVector::NoView z = A(3,_);
    z = 42;

    cout << "A = " << A << endl;
    cout << "y = " << y << endl;
    cout << "z = " << z << endl;

    auto x = A(_(2,4),2);
    x = 999;

    auto d_1 = A.diag(-1);
    auto d0  = A.diag(0);
    auto d1  = A.diag(1);
    auto d2  = A.diag(2);

    cout << "d_1 = " << d_1 << endl;
    cout << "d0  = " << d0 << endl;
    cout << "d1  = " << d1 << endl;
    cout << "d2  = " << d2 << endl;

    d0 = -1;
    d1 = -100, -200, -300, -400;

    cout << "A = " << A << endl;
    cout << "x = " << x << endl;

    cout << "A.leadingDimension() = " << A.leadingDimension() << endl;
    cout << "x.stride() = " << x.stride() << endl;
    cout << "y.stride() = " << y.stride() << endl;
    cout << "z.stride() = " << z.stride() << endl;
    cout << "d_1.stride() = " << d_1.stride() << endl;
    cout << "d0.stride()  = " << d0.stride() << endl;
    cout << "d1.stride()  = " << d1.stride() << endl;
    cout << "d2.stride()  = " << d2.stride() << endl;
}

Comments on Example Code

We define typedefs for dense vectors and general matrices that allocate their own memory.

    typedef GeMatrix<FullStorage<double, ColMajor> >    GeMatrix;
    typedef DenseVector<Array<double> >                 DenseVector;
    typedef DenseVector::IndexType                      IndexType;

For selecting vector parts we define a range operator

    const Underscore<IndexType> _;

We setup some matrix.

    GeMatrix  A(45);
    A =  1,  2,  3,  4,  5,
         6,  7,  8,  910,
        1112131415,
        1617181920;

We create a vector view y that references the second row of A. Then we reset all elements of y to 666. This will also change elements in A.

    DenseVector::View y = A(2,_);
    y = 666;

We create a “regular” vector z and initialize it with the third row of A. Just to show that z is not a view we then reset all elements of z to 42. You will see that this will not change elements in A.

    DenseVector::NoView z = A(3,_);
    z = 42;

Of course we also can use the auto type instead of writing out the DenseVector::View type.

    auto x = A(_(2,4),2);
    x = 999;

You also can reference the k-th off-diagonal of A. For \(k=0\) you get the main diagonal, for \(k>0\) the k-th super-diagonal and for \(k<0\) the corresponding sub-diagonal.

    auto d_1 = A.diag(-1);
    auto d0  = A.diag(0);
    auto d1  = A.diag(1);
    auto d2  = A.diag(2);

Next we set all elements on the diagonal to -1 and all elements on the first super-diagonal to -100, ..., -400:

    d0 = -1;
    d1 = -100, -200, -300, -400;

We finally print the strides of the vectors. Compare strides of vectors referencing rows, columns and diagonals.

    cout << "A.leadingDimension() = " << A.leadingDimension() << endl;
    cout << "x.stride() = " << x.stride() << endl;
    cout << "y.stride() = " << y.stride() << endl;
    cout << "z.stride() = " << z.stride() << endl;
    cout << "d_1.stride() = " << d_1.stride() << endl;
    cout << "d0.stride()  = " << d0.stride() << endl;
    cout << "d1.stride()  = " << d1.stride() << endl;
    cout << "d2.stride()  = " << d2.stride() << endl;
}

Compile and Run

$shell> cd flens/examples                                                     
$shell> clang++ -Wall -std=c++0x -I../.. tut01-page04-example02.cc            
$shell> ./a.out                                                               
A = 
                   1                    2                    3                    4                    5 
                 666                  666                  666                  666                  666 
                  11                   12                   13                   14                   15 
                  16                   17                   18                   19                   20 
y = 
        666          666          666          666          666 
z = 
         42           42           42           42           42 
d_1 = 
        666          999           18 
d0  = 
          1          999           13           19 
d1  = 
          2          666           14           20 
d2  = 
          3          666           15 
A = 
                  -1                 -100                    3                    4                    5 
                 666                   -1                 -200                  666                  666 
                  11                  999                   -1                 -300                   15 
                  16                  999                   18                   -1                 -400 
x = 
         -1          999          999 
A.leadingDimension() = 4
x.stride() = 1
y.stride() = 4
z.stride() = 1
d_1.stride() = 5
d0.stride()  = 5
d1.stride()  = 5
d2.stride()  = 5