From 9b2a567165e016e9d8a2139d272bc97464d828b4 Mon Sep 17 00:00:00 2001 From: Christoph Gersbacher <gersbach@dune-project.org> Date: Wed, 6 Feb 2013 15:15:22 +0000 Subject: [PATCH] Add interface check for dense matrices. [[Imported from SVN: r7101]] --- dune/common/test/Makefile.am | 2 +- dune/common/test/checkmatrixinterface.hh | 381 +++++++++++++++++++++++ 2 files changed, 382 insertions(+), 1 deletion(-) create mode 100644 dune/common/test/checkmatrixinterface.hh diff --git a/dune/common/test/Makefile.am b/dune/common/test/Makefile.am index f75aa909b..2b622e429 100644 --- a/dune/common/test/Makefile.am +++ b/dune/common/test/Makefile.am @@ -102,7 +102,7 @@ noinst_HEADERS = dummyiterator.hh # Install some test headers, because they get used by tests in other modules testincludedir = $(includedir)/dune/common/test -testinclude_HEADERS = iteratortest.hh +testinclude_HEADERS = checkmatrixinterface.hh iteratortest.hh # define the programs pathtest_SOURCES = pathtest.cc diff --git a/dune/common/test/checkmatrixinterface.hh b/dune/common/test/checkmatrixinterface.hh new file mode 100644 index 000000000..6964358a0 --- /dev/null +++ b/dune/common/test/checkmatrixinterface.hh @@ -0,0 +1,381 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_COMMON_CHECK_MATRIX_INTERFACE_HH +#define DUNE_COMMON_CHECK_MATRIX_INTERFACE_HH + +#include <algorithm> + +#include <dune/common/dynvector.hh> +#include <dune/common/exceptions.hh> +#include <dune/common/ftraits.hh> +#include <dune/common/fvector.hh> + + +/* + * @file + * @brief This file provides an interface check for dense matrices. + * @author Christoph Gersbacher + */ + + +namespace CheckMatrixInterface +{ + + namespace Capabilities + { + + // hasStaticSizes + // -------------- + + template< class Matrix > + struct hasStaticSizes + { + static const bool v = false; + static const int rows = ~0; + static const int cols = ~0; + }; + + template< class Matrix > + struct hasStaticSizes< const Matrix > + { + static const bool v = hasStaticSizes< Matrix >::v; + static const int rows = hasStaticSizes< Matrix >::rows; + static const int cols = hasStaticSizes< Matrix >::cols; + }; + + + + // isRegular + // --------- + + template< class Matrix > + struct isRegular + { + static const bool v = false; + }; + + template< class Matrix > + struct isRegular< const Matrix > + { + static const bool v = isRegular< Matrix >::v; + }; + + } // namespace Capabilities + + + + // UseDynamicVector + // ---------------- + + template< class Matrix > + struct UseDynamicVector + { + typedef typename Matrix::value_type value_type; + + typedef Dune::DynamicVector< value_type > domain_type; + typedef domain_type range_type; + + static domain_type domain ( const Matrix &matrix, value_type v = value_type() ) + { + return domain_type( matrix.M(), v ); + } + + static range_type range ( const Matrix &matrix, value_type v = value_type() ) + { + return range_type( matrix.N(), v ); + } + }; + + + + // UseFieldVector + // -------------- + + template< class K, int rows, int cols > + struct UseFieldVector + { + typedef K value_type; + + typedef Dune::FieldVector< K, cols > domain_type; + typedef Dune::FieldVector< K, rows > range_type; + + template< class Matrix > + static domain_type domain ( const Matrix &matrix, value_type v = value_type() ) + { + return domain_type( v ); + } + + template< class Matrix > + static range_type range ( const Matrix &matrix, value_type v = value_type() ) + { + return range_type( v ); + } + }; + + + + // MatrixSizeHelper + // ---------------- + + template< class Matrix, bool hasStaticSizes = Capabilities::hasStaticSizes< Matrix >::v > + struct MatrixSizeHelper; + + template< class Matrix > + struct MatrixSizeHelper< Matrix, false > + { + typedef typename Matrix::size_type size_type; + static const size_type rows ( const Matrix &matrix ) { return matrix.rows(); } + static const size_type cols ( const Matrix &matrix ) { return matrix.cols(); } + }; + + template< class Matrix > + struct MatrixSizeHelper< Matrix, true > + { + typedef typename Matrix::size_type size_type; + static const size_type rows ( const Matrix & ) { return Matrix::rows; } + static const size_type cols ( const Matrix & ) { return Matrix::cols; } + }; + + + + // CheckIfRegularMatrix + // -------------------- + + template< class Matrix, class Traits, bool isRegular = Capabilities::isRegular< Matrix >::v > + struct CheckIfRegularMatrix; + + template< class Matrix, class Traits > + struct CheckIfRegularMatrix< Matrix, Traits, false > + { + static void checkDeterminant ( const Matrix &matrix ) {} + static void checkSolve ( const Matrix &matrix ) {} + static void checkInvert ( Matrix &matrix ) {} + }; + + template< class Matrix, class Traits > + struct CheckIfRegularMatrix< Matrix, Traits, true > + { + typedef typename Matrix::value_type value_type; + + static void checkDeterminant ( const Matrix &matrix ) + { + DUNE_UNUSED value_type determinant = matrix.determinant(); + } + + static void checkSolve ( const Matrix &matrix ) + { + typename Traits::domain_type x; + const typename Traits::range_type b = Traits::range( matrix ); + matrix.solve( x, b ); + } + + static void checkInvert ( Matrix &matrix ) { matrix.invert(); } + }; + + + + // CheckConstMatrix + // ---------------- + + template< class Matrix, class Traits > + struct CheckConstMatrix + { + // required type definitions + typedef typename Matrix::size_type size_type; + + typedef typename Matrix::value_type value_type; + typedef typename Matrix::field_type field_type; + typedef typename Matrix::block_type block_type; + + typedef typename Matrix::row_type row_type; + typedef typename Matrix::row_reference row_reference; + typedef typename Matrix::const_row_reference const_row_reference; + + typedef typename Matrix::ConstIterator ConstIterator; + + static void apply ( const Matrix &matrix ) + { + checkSizes ( matrix ); + checkDataAccess ( matrix ); + checkNorms ( matrix ); + checkLinearAlgebra ( matrix ); + checkIterators ( matrix ); + + CheckIfRegularMatrix< Matrix, Traits >::checkDeterminant( matrix ); + CheckIfRegularMatrix< Matrix, Traits >::checkSolve( matrix ); + + // TODO: check solve for regular matrices + // void invert() const; + // void solve ( range_type, range_type ); + + // TODO: check comparison + // bool operator == ( const Matrix &other ); + // bool operator != ( const Matrix &other ); + } + + // check size methods + static void checkSizes ( const Matrix &matrix ) + { + DUNE_UNUSED const size_type size = matrix.size(); + const size_type rows = MatrixSizeHelper< Matrix >::rows( matrix ); + const size_type cols = MatrixSizeHelper< Matrix >::cols( matrix ); + const size_type N = matrix.N(); + const size_type M = matrix.M(); + + if( N != rows || M != cols ) + DUNE_THROW( Dune::RangeError, "Returned inconsistent sizes." ); + } + + // check read-only access to data + static void checkDataAccess ( const Matrix &matrix ) + { + const size_type size = matrix.size(); + for( size_type i = size_type( 0 ); i < size; ++i ) + DUNE_UNUSED const_row_reference row = matrix[ i ]; + + const size_type rows = MatrixSizeHelper< Matrix >::rows( matrix ); + const size_type cols = MatrixSizeHelper< Matrix >::cols( matrix ); + for( size_type i = size_type( 0 ); i < rows; ++i ) + { + for( size_type j = size_type( 0 ); j < cols; ++j ) + { + DUNE_UNUSED bool exists = matrix.exists( i, j ); + DUNE_UNUSED const value_type &value = matrix[ i ][ j ]; + } + } + } + + // check norms + static void checkNorms ( const Matrix &matrix ) + { + typedef typename Dune::FieldTraits< value_type >::real_type real_type; + real_type frobenius_norm = matrix.frobenius_norm(); + real_type frobenius_norm2 = matrix.frobenius_norm2(); + real_type infinity_norm = matrix.infinity_norm() ; + real_type infinity_norm_real = matrix.infinity_norm_real(); + + if( std::min( std::min( frobenius_norm, frobenius_norm2 ), + std::min( infinity_norm, infinity_norm_real ) ) < real_type( 0 ) ) + DUNE_THROW( Dune::InvalidStateException, "Norms must return non-negative value." ); + } + + // check basic linear algebra methods + static void checkLinearAlgebra ( const Matrix &matrix ) + { + typename Traits::domain_type domain = Traits::domain( matrix ); + typename Traits::range_type range = Traits::range( matrix ); + typename Traits::value_type alpha( 1 ); + + matrix.mv( domain, range ); + matrix.mtv( domain, range ); + matrix.umv( domain, range ); + matrix.umtv( domain, range ); + matrix.umhv( domain, range ); + matrix.mmv( domain, range ); + matrix.mmtv( domain, range ); + matrix.mmhv( domain, range ); + matrix.usmv( alpha, domain, range ); + matrix.usmtv( alpha, domain, range ); + matrix.usmhv( alpha, domain, range ); + } + + // check iterator methods + static void checkIterators ( const Matrix &matrix ) + { + const ConstIterator end = matrix.end(); + for( ConstIterator it = matrix.begin(); it != end; ++it ) + DUNE_UNUSED const_row_reference row = *it; + } + }; + + + + // CheckNonConstMatrix + // ------------------- + + template< class Matrix, class Traits > + struct CheckNonConstMatrix + { + // required type definitions + typedef typename Matrix::size_type size_type; + typedef typename Matrix::value_type value_type; + typedef typename Matrix::row_reference row_reference; + typedef typename Matrix::row_type row_type; + typedef typename Matrix::Iterator Iterator; + + static void apply ( Matrix &matrix ) + { + checkAssignment( matrix ); + checkIterators( matrix ); + + CheckIfRegularMatrix< Matrix, Traits >::checkDeterminant( matrix ); + + // TODO: check scalar/matrix and matrix/matrix operations + // Matrix &operator+= ( const Matrix &other ); + // Matrix &operator-= ( const Matrix &other ); + // Matrix &operator*= ( const value_type &v ); + // Matrix &operator/= ( const value_type &v ); + // Matrix &axpy += ( const value_type &v, const Matrix &other ); + // Matrix &axpy += ( const value_type &v, const Matrix &other ); + // Matrix &leftmultiply ( const Matrix &other ); + // Matrix &rightmultiply ( const Matrix &other ); + } + + // check assignment + static void checkAssignment ( Matrix &matrix ) + { + matrix = value_type( 1 ); + + const size_type size = matrix.size(); + for( size_type i = size_type( 0 ); i < size; ++i ) + { + row_reference row = matrix[ i ]; + row = row_type( value_type( 0 ) ); + } + + const size_type rows = MatrixSizeHelper< Matrix >::rows( matrix ); + const size_type cols = MatrixSizeHelper< Matrix >::cols( matrix ); + for( size_type i = size_type( 0 ); i < rows; ++i ) + { + for( size_type j = size_type( 0 ); j < cols; ++j ) + matrix[ i ][ j ] = ( i == j ? value_type( 1 ) : value_type( 0 ) ); + } + } + + // check iterator methods + static void checkIterators ( Matrix &matrix ) + { + const Iterator end = matrix.end(); + for( Iterator it = matrix.begin(); it != end; ++it ) + { + row_reference row = *it; + row = row_type( value_type( 0 ) ); + } + } + }; + +} // namespace CheckMatrixInterface + + +namespace Dune +{ + + // checkMatrixInterface + // -------------------- + + template< class Matrix, class Traits = CheckMatrixInterface::UseDynamicVector< Matrix > > + void checkMatrixInterface ( Matrix &matrix ) + { + CheckMatrixInterface::CheckConstMatrix< Matrix, Traits >::apply( matrix ); + CheckMatrixInterface::CheckNonConstMatrix< Matrix, Traits >::apply( matrix ); + } + + template< class Matrix, class Traits = CheckMatrixInterface::UseDynamicVector< Matrix > > + void checkMatrixInterface ( const Matrix &matrix ) + { + CheckMatrixInterface::CheckConstMatrix< Matrix, Traits >::apply( matrix ); + } + +} // namespace Dune + +#endif // #ifndef DUNE_COMMON_CHECK_MATRIX_INTERFACE_HH -- GitLab