From 38d22f814b19f91b0cf696a874c2b3b8229d7022 Mon Sep 17 00:00:00 2001
From: Uli Sack <usack@math.fu-berlin.de>
Date: Tue, 10 Jan 2012 15:36:49 +0000
Subject: [PATCH] now, here are the classes and tests

[[Imported from SVN: r5238]]
---
 dune/solvers/operators/Makefile.am        |   8 +
 dune/solvers/operators/lowrankoperator.hh |  57 +++++++
 dune/solvers/operators/nulloperator.hh    |  87 +++++++++++
 dune/solvers/operators/sumoperator.hh     |  62 ++++++++
 dune/solvers/test/Makefile.am             |  38 +++++
 dune/solvers/test/lowrankoperatortest.cc  | 172 ++++++++++++++++++++++
 dune/solvers/test/nulloperatortest.cc     | 104 +++++++++++++
 dune/solvers/test/sumoperatortest.cc      | 157 ++++++++++++++++++++
 8 files changed, 685 insertions(+)
 create mode 100644 dune/solvers/operators/Makefile.am
 create mode 100644 dune/solvers/operators/lowrankoperator.hh
 create mode 100644 dune/solvers/operators/nulloperator.hh
 create mode 100644 dune/solvers/operators/sumoperator.hh
 create mode 100644 dune/solvers/test/Makefile.am
 create mode 100644 dune/solvers/test/lowrankoperatortest.cc
 create mode 100644 dune/solvers/test/nulloperatortest.cc
 create mode 100644 dune/solvers/test/sumoperatortest.cc

diff --git a/dune/solvers/operators/Makefile.am b/dune/solvers/operators/Makefile.am
new file mode 100644
index 00000000..e1c13db9
--- /dev/null
+++ b/dune/solvers/operators/Makefile.am
@@ -0,0 +1,8 @@
+SUBDIRS =
+
+operatorsdir = $(includedir)/dune/solvers/operators
+operators_HEADERS = lowrankoperator.hh \
+                    nulloperator.hh \
+                    sumoperator.hh
+
+include $(top_srcdir)/am/global-rules
diff --git a/dune/solvers/operators/lowrankoperator.hh b/dune/solvers/operators/lowrankoperator.hh
new file mode 100644
index 00000000..916112d3
--- /dev/null
+++ b/dune/solvers/operators/lowrankoperator.hh
@@ -0,0 +1,57 @@
+#ifndef LOWRANKOPERATOR_HH
+#define LOWRANKOPERATOR_HH
+
+
+/** \brief Class that behaves like a filled in low-rank matrix defined via a factor \f$ M\in\mathbb R^{k\times n}, k<<n \f$
+ *
+ *  The full matrix is given by \f$ A=M^TM\f$
+ *
+ *  \tparam LRFactorType The (Matrix-) type of the defining factor M
+ */
+template <class LRFactorType>
+class LowRankOperator
+{
+    public:
+        //! export the type of the defining factor
+        typedef LRFactorType LowRankFactorType;
+
+        //! constructor taking the defining factor as argument
+        LowRankOperator(LowRankFactorType& lrFactor):
+            lowRankFactor_(lrFactor)
+        {}
+
+        //! b += Ax
+        template <class LVectorType, class RVectorType>
+        void umv(const LVectorType& x, RVectorType& b) const
+        {
+            LVectorType temp(lowRankFactor_.N());
+            lowRankFactor_.mv(x,temp);
+
+            for (size_t i=0; i<b.size(); ++i)
+                for (size_t j=0; j<lowRankFactor_.N(); ++j)
+                    if (lowRankFactor_.exists(j,i))
+                        lowRankFactor_[j][i].umv(temp[j],b[i]);
+        }
+
+        //! b = Ax
+        template <class LVectorType, class RVectorType>
+        void mv(const LVectorType& x, RVectorType& b) const
+        {
+            b = 0.0;
+            umv(x,b);
+        }
+
+        //! returns the defining factor
+        const LowRankFactorType& getLowRankFactor() const
+        {
+            return lowRankFactor_;
+        }
+
+    private:
+        //! the defining factor
+        LowRankFactorType& lowRankFactor_;
+
+};
+
+#endif
+
diff --git a/dune/solvers/operators/nulloperator.hh b/dune/solvers/operators/nulloperator.hh
new file mode 100644
index 00000000..f9b2888b
--- /dev/null
+++ b/dune/solvers/operators/nulloperator.hh
@@ -0,0 +1,87 @@
+#ifndef NULLOPERATOR_HH
+#define NULLOPERATOR_HH
+
+/** \brief Represents the null operator in the needed space
+ *
+ */
+template <class BlockType>
+class NullOperator
+{
+    private:
+        /** \brief A dummy class for the rows
+         *
+         *  Contains a zero block to refer to
+         */
+        class RowDummy
+        {
+            private:
+                BlockType zero_;
+
+            public:
+                RowDummy(): zero_(0){};
+
+                const BlockType& operator[](size_t i) const
+                {
+                    return zero_;
+                }
+        };
+
+        //! a dummy row
+        RowDummy rowDummy_;
+
+    public:
+        //! export the block type
+        typedef BlockType block_type;
+
+        //! Default constructor
+        NullOperator(){}
+
+        /** \brief constructor taking anything
+         *
+         *  This is here to allow for NullOperator as block_type (this is needed in the constructor of RowDummy)
+         */
+        template <class T>
+        NullOperator(const T& t){}
+
+        /** \brief Matrix-Vector multiplication
+         *
+         *  Implements b += Nx and hence does nothing (N=0 !)
+         */
+        template <class LVectorType, class RVectorType>
+        void umv(const LVectorType& x, RVectorType& b) const
+        {}
+
+        /** \brief Matrix-Vector multiplication with scalar multiplication
+         *
+         *  Implements b += a*Nx and hence does nothing (N=0 !)
+         */
+        template <class LVectorType, class RVectorType>
+        void usmv(const double a, const LVectorType& x, RVectorType& b) const
+        {}
+
+        /** \brief Matrix-Vector multiplication
+         *
+         *  Implements b = Nx and hence does nothing but set b=0 (N=0 !)
+         */
+        template <class LVectorType, class RVectorType>
+        void mv(const LVectorType& x, RVectorType& b) const
+        {
+            b = 0.0;
+        }
+
+        //! random access operator
+        const RowDummy& operator[](size_t i) const
+        {
+            return rowDummy_;
+        }
+
+        //! return j-th diagonal entry
+        const block_type& diagonal(size_t i) const
+        {
+            return rowDummy_[0];
+        }
+
+};
+
+#endif
+
diff --git a/dune/solvers/operators/sumoperator.hh b/dune/solvers/operators/sumoperator.hh
new file mode 100644
index 00000000..7869d376
--- /dev/null
+++ b/dune/solvers/operators/sumoperator.hh
@@ -0,0 +1,62 @@
+#ifndef SUMOPERATOR_HH
+#define SUMOPERATOR_HH
+
+/** \brief represents the sum of two linear operators
+ *
+ *  The summands may be of arbitrary type. Their names are for historical illustrative reasons where one is a sparse and the other a filled in lowrank matrix
+ *  \tparam SparseMatrix the type of one of the summands
+ *  \tparam LowRankMatrix the type of the other summand
+ */
+template <class SparseMatrix, class LowRankMatrix>
+class SumOperator
+{
+    public:
+        //! export the summand type
+        typedef SparseMatrix SparseMatrixType;
+        //! export the summand type
+        typedef LowRankMatrix LowRankMatrixType;
+
+        //! construct from summands
+        SumOperator(SparseMatrixType& A, LowRankMatrixType& M):
+            sparse_matrix_(A),
+            lowrank_matrix_(M)
+        {}
+
+        //! b += (A+M)x
+        template <class LVectorType, class RVectorType>
+        void umv(const LVectorType& x, RVectorType& b) const
+        {
+            sparse_matrix_.umv(x,b);
+            lowrank_matrix_.umv(x,b);
+        }
+
+        //! b = (A+M)x
+        template <class LVectorType, class RVectorType>
+        void mv(const LVectorType& x, RVectorType& b)
+        {
+            sparse_matrix_.mv(x,b);
+            lowrank_matrix_.umv(x,b);
+        }
+
+        //! return one summand
+        SparseMatrixType& getSparseMatrix()
+        {
+            return sparse_matrix_;
+        }
+
+        //! return "the other" summand
+        LowRankMatrixType& getLowRankMatrix()
+        {
+            return lowrank_matrix_;
+        }
+
+    private:
+        //! one summand
+        SparseMatrixType&  sparse_matrix_;
+        //! the other summand
+        LowRankMatrixType& lowrank_matrix_;
+
+};
+
+#endif
+
diff --git a/dune/solvers/test/Makefile.am b/dune/solvers/test/Makefile.am
new file mode 100644
index 00000000..df9e99f2
--- /dev/null
+++ b/dune/solvers/test/Makefile.am
@@ -0,0 +1,38 @@
+
+# list of tests to run
+TESTS = lowrankoperatortest \
+        nulloperatortest \
+        sumoperatortest
+
+# programs just to build when "make check" is used
+check_PROGRAMS = $(TESTS)
+
+noinst_HEADERS =
+
+# collect some common flags
+COMMON_CPPFLAGS = $(AM_CPPFLAGS) $(DUNEMPICPPFLAGS)
+COMMON_LDADD =  $(DUNE_LDFLAGS) $(DUNE_LIBS) $(DUNEMPILIBS) $(LDADD)
+COMMON_LDFLAGS = $(AM_LDFLAGS) $(DUNEMPILDFLAGS) $(DUNE_LDFLAGS)
+
+GRID_CPPFLAGS =  $(UG_CPPFLAGS) $(ALUGRID_CPPFLAGS)
+GRID_LDADD =  $(UG_LDFLAGS) $(UG_LIBS) $(ALUGRID_LDFLAGS) $(ALUGRID_LIBS)
+GRID_LDFLAGS =  $(UG_LDFLAGS) $(ALUGRID_LDFLAGS)
+
+
+# define the programs
+lowrankoperatortest_SOURCES = lowrankoperatortest.cc
+lowrankoperatortest_CPPFLAGS = $(COMMON_CPPFLAGS) $(GRID_CPPFLAGS)
+lowrankoperatortest_LDADD = $(COMMON_LDADD) $(GRID_LDADD)
+lowrankoperatortest_LDFLAGS = $(COMMON_LDFLAGS) $(GRID_LDFLAGS)
+
+nulloperatortest_SOURCES = nulloperatortest.cc
+nulloperatortest_CPPFLAGS = $(COMMON_CPPFLAGS) $(GRID_CPPFLAGS)
+nulloperatortest_LDADD = $(COMMON_LDADD) $(GRID_LDADD)
+nulloperatortest_LDFLAGS = $(COMMON_LDFLAGS) $(GRID_LDFLAGS)
+
+sumoperatortest_SOURCES = sumoperatortest.cc
+sumoperatortest_CPPFLAGS = $(COMMON_CPPFLAGS) $(GRID_CPPFLAGS)
+sumoperatortest_LDADD = $(COMMON_LDADD) $(GRID_LDADD)
+sumoperatortest_LDFLAGS = $(COMMON_LDFLAGS) $(GRID_LDFLAGS)
+
+include $(top_srcdir)/am/global-rules
diff --git a/dune/solvers/test/lowrankoperatortest.cc b/dune/solvers/test/lowrankoperatortest.cc
new file mode 100644
index 00000000..8a456e29
--- /dev/null
+++ b/dune/solvers/test/lowrankoperatortest.cc
@@ -0,0 +1,172 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <cmath>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+
+#include <dune/istl/bvector.hh>
+#include <dune/istl/matrix.hh>
+#include <dune/istl/diagonalmatrix.hh>
+#include <dune/istl/scaledidmatrix.hh>
+#include <dune/istl/io.hh>
+
+#include <dune/solvers/operators/lowrankoperator.hh>
+
+#define BLOCKSIZE 2
+
+// This tests the LowRankOperator's methods for consistency with corresponding operations of the full matrix
+template <class StaticMatrixType>
+class MatrixMultiplier
+{
+    public:
+        static StaticMatrixType matXmat(const StaticMatrixType& A, const StaticMatrixType& B)
+        {
+            DUNE_THROW(Dune::NotImplemented,"MatXmat not implemented for this MatrixType.");
+        }
+};
+
+template <class field_type, int N>
+class MatrixMultiplier<Dune::ScaledIdentityMatrix<field_type,N> >
+{
+        typedef Dune::ScaledIdentityMatrix<field_type,N> StaticMatrixType;
+    public:
+        static StaticMatrixType matXmat(const StaticMatrixType& A, const StaticMatrixType& B)
+        {
+            return StaticMatrixType(A.scalar()*B.scalar());
+        }
+        static StaticMatrixType matTXmat(const StaticMatrixType& A, const StaticMatrixType& B)
+        {
+            return matXmat(A,B);
+        }
+};
+
+template <class field_type, int N>
+class MatrixMultiplier<Dune::DiagonalMatrix<field_type,N> >
+{
+        typedef Dune::DiagonalMatrix<field_type,N> StaticMatrixType;
+    public:
+        static StaticMatrixType matXmat(const StaticMatrixType& A, const StaticMatrixType& B)
+        {
+            StaticMatrixType r(A);
+            for (size_t i=0; i<N; ++i)
+                r.diagonal(i) *= B.diagonal(i);
+            return r;
+        }
+        static StaticMatrixType matTXmat(const StaticMatrixType& A, const StaticMatrixType& B)
+        {
+            return matXmat(A,B);
+        }
+};
+
+
+template <class LowRankFactorType>
+bool check()
+{
+
+    bool passed = true;
+    typedef typename LowRankFactorType::block_type block_type;
+    size_t block_size = block_type::rows;
+
+    size_t m=3, n=1000;
+    typedef Dune::FieldVector<double, block_type::rows> Vblock_type;
+    typedef Dune::BlockVector<Vblock_type> Vector;
+
+    Vector x(n), b(n), ref_vec(n);
+    for (size_t i = 0; i<n; ++i)
+//        x[i] = 1.0;
+        x[i] = (1.0*rand()) / RAND_MAX;
+    b = ref_vec = 0.0;
+
+    LowRankFactorType lr_factor(m,n);
+    std::cout << "Checking LowRankOperator<" << Dune::className(lr_factor) << " >  ...  ";
+
+    // set lowrankfactor to random values
+    typedef typename block_type::RowIterator BlockRowIterator;
+    typedef typename block_type::ColIterator BlockColIterator;
+    for (size_t row=0; row<m; ++row)
+        for (size_t col=0; col<n; ++col)
+        {
+            BlockRowIterator row_end = lr_factor[row][col].end();
+            for (BlockRowIterator row_it = lr_factor[row][col].begin(); row_it!=row_end; ++ row_it)
+            {
+                BlockColIterator col_end = row_it->end();
+                for (BlockColIterator col_it = row_it->begin(); col_it!=col_end; ++col_it)
+//                    *col_it = col+1;
+                    *col_it = (1.0*rand())/RAND_MAX;
+            }
+        }
+
+    LowRankOperator<LowRankFactorType> lr_op(lr_factor);
+
+    LowRankFactorType full_op(n,n);
+
+    for (size_t i=0; i<n; ++i)
+        for (size_t j=0; j<n; ++j)
+        {
+            if (j>=i)
+            {
+                full_op[i][j] = 0.0;
+                for (size_t k=0; k<m; ++k)
+                {
+                    full_op[i][j] += MatrixMultiplier<block_type>::matTXmat(lr_factor[k][i], lr_factor[k][j]);
+                }
+            }
+            else
+                full_op[i][j] = full_op[j][i];
+        }
+
+    full_op.mv(x,ref_vec);
+
+    lr_op.umv(x,b);
+    for (size_t i=0; i<b.size(); ++i)
+    if ((b[i] - ref_vec[i]).two_norm()/b[i].two_norm()>1e-12)
+    {
+        std::cout << "LowRankOperator::umv does not yield correct result. Difference = " << (b[i] - ref_vec[i]).two_norm() << std::endl;
+        passed = false;
+        for (size_t j=0; j<b.size(); ++j)
+            std::cout << b[j] << "     "<<ref_vec[j] << std::endl;
+        std::cout << std::endl;
+        break;
+    }
+
+    b=1.0;
+    lr_op.mv(x,b);
+    for (size_t i=0; i<b.size(); ++i)
+    if ((b[i] - ref_vec[i]).two_norm()/b[i].two_norm()>1e-12)
+    {
+        std::cout << "LowRankOperator::mv does not yield correct result." << std::endl;
+        passed = false;
+        break;
+    }
+
+    LowRankFactorType lr_factor_reborn = lr_op.getLowRankFactor();
+
+    if (passed)
+        std::cout << "passed";
+    std::cout << std::endl;
+    return passed;
+}
+
+int main(int argc, char** argv) try
+{
+    static const int block_size = BLOCKSIZE;
+
+    bool passed(true);
+
+    passed = check<Dune::Matrix<Dune::ScaledIdentityMatrix<double, block_size> > >();
+    passed = passed and check<Dune::Matrix<Dune::DiagonalMatrix<double, block_size> > >();
+
+    return passed ? 0 : 1;
+}
+
+catch (Dune::Exception e) {
+
+    std::cout << e << std::endl;
+
+ }
+
+
+
diff --git a/dune/solvers/test/nulloperatortest.cc b/dune/solvers/test/nulloperatortest.cc
new file mode 100644
index 00000000..c7f345cd
--- /dev/null
+++ b/dune/solvers/test/nulloperatortest.cc
@@ -0,0 +1,104 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <cmath>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/fvector.hh>
+#include <dune/istl/bvector.hh>
+
+#include <dune/common/fmatrix.hh>
+#include <dune/istl/diagonalmatrix.hh>
+#include <dune/istl/scaledidmatrix.hh>
+
+#include <dune/solvers/operators/nulloperator.hh>
+
+#define BLOCKSIZE 2
+
+// this test tests the NullOperator class for several square block_types.
+// The test is mainly there to check if it compiles. It uses all implemented methods of NullOperator and
+// checks whether they come up with the expected behaviour.
+
+template <class Mblock_type>
+bool check()
+{
+    size_t block_size = Mblock_type::rows;
+    size_t n=1000;
+    typedef Dune::FieldVector<double, Mblock_type::rows> Vblock_type;
+    typedef Dune::BlockVector<Vblock_type> Vector;
+
+    Vector x(n), b(n), null_vec(n);
+    for (size_t i = 0; i<n; ++i)
+        x[i] = (1.0*rand()) / RAND_MAX;
+    b = null_vec = 0.0;
+
+    NullOperator<Mblock_type> null_op;
+
+    null_op.umv(x,b);
+    for (size_t i=0; i<b.size(); ++i)
+    if (b[i] != null_vec[i])
+    {
+        std::cout << "NullOperator::umv does not leave second argument unchanged." << std::endl;
+        return false;
+    }
+
+    null_op.usmv(1.0,x,b);
+    for (size_t i=0; i<b.size(); ++i)
+    if (b[i] != null_vec[i])
+    {
+        std::cout << "NullOperator::usmv does not leave second argument unchanged." << std::endl;
+        return false;
+    }
+
+    b=1.0;
+    null_op.mv(x,b);
+    for (size_t i=0; i<b.size(); ++i)
+    if (b[i] != null_vec[i])
+    {
+        std::cout << "NullOperator::mv does not set second argument to zero." << std::endl;
+        return false;
+    }
+
+    Mblock_type zero_block(0);
+
+    {
+        const Mblock_type block(null_op[n/2][n/4]);
+        if (block != zero_block)
+        {
+            std::cout << "NullOperator[][] does not yield correct zero block" << std::endl;
+            return false;
+        }
+    }
+
+    {
+        const Mblock_type block(null_op.diagonal(n/4));
+        if (block != zero_block)
+        {
+            std::cout << "NullOperator::diagonal does not yield correct zero block" << std::endl;
+            return false;
+        }
+    }
+
+    return true;
+}
+
+int main(int argc, char** argv) try
+{
+    static const int block_size = BLOCKSIZE;
+
+    bool passed;
+
+    passed = check<Dune::ScaledIdentityMatrix<double, block_size> >();
+    passed = passed and check<Dune::DiagonalMatrix<double, block_size> >();
+    passed = passed and check<Dune::FieldMatrix<double, block_size, block_size> >();
+
+    return passed ? 0 : 1;
+}
+
+catch (Dune::Exception e) {
+
+    std::cout << e << std::endl;
+
+ }
+
+
diff --git a/dune/solvers/test/sumoperatortest.cc b/dune/solvers/test/sumoperatortest.cc
new file mode 100644
index 00000000..4ec4c848
--- /dev/null
+++ b/dune/solvers/test/sumoperatortest.cc
@@ -0,0 +1,157 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <cmath>
+
+#include <dune/common/exceptions.hh>
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+
+#include <dune/istl/bvector.hh>
+#include <dune/istl/matrix.hh>
+#include <dune/istl/diagonalmatrix.hh>
+#include <dune/istl/scaledidmatrix.hh>
+#include <dune/istl/io.hh>
+
+#include <dune/solvers/operators/sumoperator.hh>
+#include <dune/solvers/operators/lowrankoperator.hh>
+
+#define BLOCKSIZE 2
+
+// This tests the SumOperator's methods for consistency with successive execution of corresponding operations
+template <class SparseMatrixType, class LowRankFactorType>
+bool check()
+{
+
+    bool passed = true;
+    typedef typename SparseMatrixType::block_type  sp_block_type;
+    typedef typename LowRankFactorType::block_type lr_block_type;
+    size_t block_size = sp_block_type::rows;
+
+    assert(block_size==lr_block_type::rows);
+
+    size_t m=1, n=2;
+    typedef Dune::FieldVector<typename sp_block_type::field_type, sp_block_type::rows> Vblock_type;
+    typedef Dune::BlockVector<Vblock_type> Vector;
+
+    Vector x(n), b(n), ref_vec(n);
+    for (size_t i = 0; i<n; ++i)
+//        x[i] = 1.0;
+        x[i] = (1.0*rand()) / RAND_MAX;
+    b = ref_vec = 0.0;
+
+    LowRankFactorType lr_factor(m,n);
+    SparseMatrixType sparse_matrix(n,n,4,SparseMatrixType::row_wise);
+
+    // create sparse Matrix as tridiagonal matrix
+    typedef typename SparseMatrixType::CreateIterator Iter;
+    Iter c_end = sparse_matrix.createend();
+    for(Iter row=sparse_matrix.createbegin(); row!=c_end; ++row)
+    {
+        // Add nonzeros for left neighbour, diagonal and right neighbour
+        if(row.index()>0)
+            row.insert(row.index()-1);
+        row.insert(row.index());
+        if(row.index()<sparse_matrix.N()-1)
+            row.insert(row.index()+1);
+    }
+
+     // Now the sparsity pattern is fully set up and we can add values
+    for (size_t i=0; i<n; ++i)
+    {
+        if (i>0)
+            sparse_matrix[i][i-1] = (1.0*rand())/RAND_MAX;
+        sparse_matrix[i][i]= (1.0*rand())/RAND_MAX;
+        if (i<n-1)
+            sparse_matrix[i][i+1] = (1.0*rand())/RAND_MAX;
+    }
+
+    // set lowrankfactor to random values
+    typedef typename lr_block_type::RowIterator BlockRowIterator;
+    typedef typename lr_block_type::ColIterator BlockColIterator;
+    for (size_t row=0; row<m; ++row)
+        for (size_t col=0; col<n; ++col)
+        {
+            BlockRowIterator row_end = lr_factor[row][col].end();
+            for (BlockRowIterator row_it = lr_factor[row][col].begin(); row_it!=row_end; ++ row_it)
+            {
+                BlockColIterator col_end = row_it->end();
+                for (BlockColIterator col_it = row_it->begin(); col_it!=col_end; ++col_it)
+//                    *col_it = col+1;
+                    *col_it = (1.0*rand())/RAND_MAX;
+            }
+        }
+
+    LowRankOperator<LowRankFactorType> lr_op(lr_factor);
+
+    std::cout << "Checking SumOperator<" << Dune::className(sparse_matrix) << ", " << Dune::className(lr_op) << " >  ...  ";
+
+    SumOperator<SparseMatrixType,LowRankOperator<LowRankFactorType> > sum_op(sparse_matrix, lr_op);
+
+
+    lr_op.umv(x,ref_vec);
+    sparse_matrix.umv(x,ref_vec);
+
+    sum_op.umv(x,b);
+    for (size_t i=0; i<b.size(); ++i)
+    if ((b[i] - ref_vec[i]).two_norm()>1e-15)
+    {
+        std::cout << "SumOperator::umv does not yield correct result." << std::endl;
+        passed = false;
+        for (size_t j=0; j<b.size(); ++j)
+            std::cout << b[j] << "     "<<ref_vec[j] << std::endl;
+        std::cout << std::endl;
+        break;
+    }
+
+    b=1.0;
+
+    sum_op.mv(x,b);
+    for (size_t i=0; i<b.size(); ++i)
+    if ((b[i] - ref_vec[i]).two_norm()>1e-15)
+    {
+        std::cout << "SumOperator::mv does not yield correct result." << std::endl;
+        passed = false;
+        break;
+    }
+
+    LowRankOperator<LowRankFactorType> lr_factor_reborn = sum_op.getLowRankMatrix();
+    SparseMatrixType sparse_matrix_reborn = sum_op.getSparseMatrix();
+
+    if (passed)
+        std::cout << "passed";
+    std::cout << std::endl;
+    return passed;
+}
+
+int main(int argc, char** argv) try
+{
+    static const int block_size = BLOCKSIZE;
+
+    bool passed(true);
+
+    typedef Dune::ScaledIdentityMatrix<double, block_size>    Block1;
+    typedef Dune::DiagonalMatrix<double, block_size>          Block2;
+    typedef Dune::FieldMatrix<double, block_size, block_size> Block3;
+
+    passed =            check<Dune::BCRSMatrix<Block1>, Dune::Matrix<Block1> >();
+    passed = passed and check<Dune::BCRSMatrix<Block1>, Dune::Matrix<Block2> >();
+    passed = passed and check<Dune::BCRSMatrix<Block1>, Dune::Matrix<Block3> >();
+
+    passed = passed and check<Dune::BCRSMatrix<Block2>, Dune::Matrix<Block1> >();
+    passed = passed and check<Dune::BCRSMatrix<Block2>, Dune::Matrix<Block2> >();
+    passed = passed and check<Dune::BCRSMatrix<Block2>, Dune::Matrix<Block3> >();
+
+    passed = passed and check<Dune::BCRSMatrix<Block3>, Dune::Matrix<Block1> >();
+    passed = passed and check<Dune::BCRSMatrix<Block3>, Dune::Matrix<Block2> >();
+    passed = passed and check<Dune::BCRSMatrix<Block3>, Dune::Matrix<Block3> >();
+
+    return passed ? 0 : 1;
+}
+
+catch (Dune::Exception e) {
+
+    std::cout << e << std::endl;
+
+ }
+
-- 
GitLab