Content

Using FLENS-BLAS through Overloaded Operators

Toy Example

We use the same example as before, i.e. we compute \(y = \beta y + \alpha\,A^T x + z\) where \(\alpha, \beta\) are scalars, \(x, y, z\) are (dense) vectors and \(A\) is a (general) matrix (with full storage).

This time we just code it the natural way, i.e. as y = beta*y + alpha*transpose(A)*x + z and hope the best.

However, afterwards we want to check how FLENS-BLAS was internally utilized for the evaluation of the linear algebra expression. We therefore log the evaluation.

Example Code

#ifndef FLENS_DEBUG_CLOSURES
#define FLENS_DEBUG_CLOSURES
#endif

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

using namespace flens;
using namespace std;

int
main()
{
    typedef double                               T;
    typedef DenseVector<Array<T> >               DEVector;
    typedef GeMatrix<FullStorage<T, ColMajor> >  GEMatrix;

    const T  alpha = 1.5,
             beta = 2.5;

    DEVector x(3), y(3), z(3);
    x = 123;
    y = 234;
    z = 345;

    GEMatrix A(3,3);
    A = 123,
        567,
        543;

    verbose::ClosureLog::start("mylogfile");

    y = beta*y + alpha*transpose(A)*x + z;

    cout << "y = " << y << endl;

    verbose::ClosureLog::stop();

    return 0;
}

Comments on Example Code

Define the macro for debugging closures

#ifndef FLENS_DEBUG_CLOSURES
#define FLENS_DEBUG_CLOSURES
#endif

We turn on logging of the closure evaluation, i.e. the evaluation of linear algebra expressions that are coded through overloaded operators.

    verbose::ClosureLog::start("mylogfile");

Compute \(y = \beta y + \alpha A^T x + z\)

    y = beta*y + alpha*transpose(A)*x + z;

Stop logging.

    verbose::ClosureLog::stop();

Compile, Run and Examining the Log-File

Compiling the code becomes slightly more complex. But we hope the comments give enough glues to see what need to be done.

$shell> cd flens/examples                                                     
$shell> #                                                                     
$shell> # cleanup old object files and compile some stuff needed for logging  
$shell> #                                                                     
$shell> rm -f *.o                                                             
$shell> g++ -Wall -std=c++11 -I../.. -c ../../flens/debug/auxiliary/*.cc      
$shell> #                                                                     
$shell> # compile with -DFLENS_DEBUG_CLOSURES and link against the log stuff  
$shell> #                                                                     
$shell> g++ -Wall -std=c++11 -I../.. *.o tut02-page03-example.cc              
$shell> ./a.out                                                               
y = 
           47           50.5             54 
$shell> #                                                                     
$shell> # look what is in the log file                                        
$shell> #                                                                     
$shell> cat mylogfile                                                         
--------------------------------------------------------------------------------
x1 = (((2.5 * x1) + ((1.5 * (A1)^T) * x3)) + x2);
flens::assign((((2.5 * x1) + ((1.5 * (A1)^T) * x3)) + x2), x1);
    flens::blas::copy((((2.5 * x1) + ((1.5 * (A1)^T) * x3)) + x2), x1);
        flens::blas::copy(((2.5 * x1) + ((1.5 * (A1)^T) * x3)), x1);
            --> flens::blas::mv(Trans, 1.5, A1, x3, 2.5, x1);
        --> flens::blas::axpy(1, x2, x1);

In the log files you see a complete trace of function calls. If you compile with -DNDEBUG instead most of these functions get inlined and only the functions marked with the arrows --> actually get called. Not that this means that in non-debug mode the resulting code is equivalent to calling CXXBLAS directly.

Note: The logging mechanism in FLENS gives different matrix/vector objects unique names. The letter represents the matrix/vector types:

Letter

Matrix/Vector Type

x

DenseVector

A

GeMatrix

T

TrMatrix

S

SyMatrix

Further, vectors and matrices of same type receive subsequent numbers (like in this example vectors receive names x1, x2, x3).