From dc9153fb2ebb179731bd37051c80e77c78dc1e4c Mon Sep 17 00:00:00 2001 From: Elias Pipping <elias.pipping@fu-berlin.de> Date: Mon, 25 Jul 2016 11:47:01 +0200 Subject: [PATCH] Incorporate addProduct from Arithmetic --- dune/matrix-vector/CMakeLists.txt | 3 + dune/matrix-vector/axpy.hh | 462 +++++++++++++++++++++++++++++ dune/matrix-vector/matrixtraits.hh | 55 ++++ dune/matrix-vector/scalartraits.hh | 44 +++ 4 files changed, 564 insertions(+) create mode 100644 dune/matrix-vector/axpy.hh create mode 100644 dune/matrix-vector/matrixtraits.hh create mode 100644 dune/matrix-vector/scalartraits.hh diff --git a/dune/matrix-vector/CMakeLists.txt b/dune/matrix-vector/CMakeLists.txt index 7a7517e..3ffe97f 100644 --- a/dune/matrix-vector/CMakeLists.txt +++ b/dune/matrix-vector/CMakeLists.txt @@ -1,7 +1,10 @@ #install headers install(FILES + axpy.hh componentwisematrixmap.hh genericvectortools.hh + matrixtraits.hh + scalartraits.hh singlenonzerocolumnmatrix.hh singlenonzerorowmatrix.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/matrix-vector) \ No newline at end of file diff --git a/dune/matrix-vector/axpy.hh b/dune/matrix-vector/axpy.hh new file mode 100644 index 0000000..792dc03 --- /dev/null +++ b/dune/matrix-vector/axpy.hh @@ -0,0 +1,462 @@ +#ifndef DUNE_MATRIX_VECTOR_AXPY_HH +#define DUNE_MATRIX_VECTOR_AXPY_HH + +#include <type_traits> + +#include <dune/common/diagonalmatrix.hh> +#include <dune/common/fmatrix.hh> +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/scaledidmatrix.hh> + +#include "matrixtraits.hh" +#include "scalartraits.hh" + +namespace Dune { +namespace MatrixVector { + /** \brief Internal helper class for product operations + * + */ + template <class A, class B, class C, bool AisScalar, bool BisScalar, + bool CisScalar> + struct ProductHelper { + template < + class ADummy = A, + std::enable_if_t<!MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const B& b, const C& c) { + b.umv(c, a); + } + + template < + class ADummy = A, + std::enable_if_t<MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const B& b, const C& c) { + typename B::ConstRowIterator bi = b.begin(); + typename B::ConstRowIterator bEnd = b.end(); + for (; bi != bEnd; ++bi) { + typename B::ConstColIterator bik = bi->begin(); + typename B::ConstColIterator biEnd = bi->end(); + for (; bik != biEnd; ++bik) { + typename C::ConstColIterator ckj = c[bik.index()].begin(); + typename C::ConstColIterator ckEnd = c[bik.index()].end(); + for (; ckj != ckEnd; ++ckj) + a[bi.index()][ckj.index()] += (*bik) * (*ckj); + } + } + } + }; + + // Internal helper class for scaled product operations (i.e., b is always a + // scalar) + template <class A, class Scalar, class B, class C, bool AisScalar, + bool BisScalar, bool CisScalar> + struct ScaledProductHelper { + template < + class ADummy = A, + std::enable_if_t<!MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const Scalar& scalar, const B& b, const C& c) { + b.usmv(scalar, c, a); + } + + template < + class ADummy = A, + std::enable_if_t<MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const Scalar& scalar, const B& b, const C& c) { + typename B::ConstRowIterator bi = b.begin(); + typename B::ConstRowIterator bEnd = b.end(); + for (; bi != bEnd; ++bi) { + typename B::ConstColIterator bik = b[bi.index()].begin(); + typename B::ConstColIterator biEnd = b[bi.index()].end(); + for (; bik != biEnd; ++bik) { + typename C::ConstColIterator ckj = c[bik.index()].begin(); + typename C::ConstColIterator ckEnd = c[bik.index()].end(); + for (; ckj != ckEnd; ++ckj) + a[bi.index()][ckj.index()] += scalar * (*bik) * (*ckj); + } + } + } + }; + + template <class T, int n, int m, int k> + struct ProductHelper<Dune::FieldMatrix<T, n, k>, Dune::FieldMatrix<T, n, m>, + Dune::FieldMatrix<T, m, k>, false, false, false> { + typedef Dune::FieldMatrix<T, n, k> A; + typedef Dune::FieldMatrix<T, n, m> B; + typedef Dune::FieldMatrix<T, m, k> C; + static void addProduct(A& a, const B& b, const C& c) { + for (size_t row = 0; row < n; ++row) { + for (size_t col = 0; col < k; ++col) { + for (size_t i = 0; i < m; ++i) + a[row][col] += b[row][i] * c[i][col]; + } + } + } + }; + + template <class T, int n, int m, int k> + struct ScaledProductHelper<Dune::FieldMatrix<T, n, k>, T, + Dune::FieldMatrix<T, n, m>, + Dune::FieldMatrix<T, m, k>, false, false, false> { + typedef Dune::FieldMatrix<T, n, k> A; + typedef Dune::FieldMatrix<T, n, m> C; + typedef Dune::FieldMatrix<T, m, k> D; + static void addProduct(A& a, const T& b, const C& c, const D& d) { + for (size_t row = 0; row < n; ++row) { + for (size_t col = 0; col < k; ++col) { + for (size_t i = 0; i < m; ++i) + a[row][col] += b * c[row][i] * d[i][col]; + } + } + } + }; + + template <class T, int n> + struct ProductHelper<Dune::DiagonalMatrix<T, n>, Dune::DiagonalMatrix<T, n>, + Dune::DiagonalMatrix<T, n>, false, false, false> { + typedef Dune::DiagonalMatrix<T, n> A; + typedef A B; + typedef B C; + static void addProduct(A& a, const B& b, const C& c) { + for (size_t i = 0; i < n; ++i) + a.diagonal(i) += b.diagonal(i) * c.diagonal(i); + } + }; + + template <class T, int n> + struct ScaledProductHelper<Dune::DiagonalMatrix<T, n>, T, + Dune::DiagonalMatrix<T, n>, + Dune::DiagonalMatrix<T, n>, false, false, false> { + typedef Dune::DiagonalMatrix<T, n> A; + typedef A C; + typedef C D; + static void addProduct(A& a, const T& b, const C& c, const D& d) { + for (size_t i = 0; i < n; ++i) + a.diagonal(i) += b * c.diagonal(i) * d.diagonal(i); + } + }; + + template <class T, int n> + struct ProductHelper<Dune::FieldMatrix<T, n, n>, Dune::DiagonalMatrix<T, n>, + Dune::DiagonalMatrix<T, n>, false, false, false> { + typedef Dune::FieldMatrix<T, n, n> A; + typedef Dune::DiagonalMatrix<T, n> B; + typedef B C; + static void addProduct(A& a, const B& b, const C& c) { + for (size_t i = 0; i < n; ++i) + a[i][i] += b.diagonal(i) * c.diagonal(i); + } + }; + + template <class T, int n> + struct ScaledProductHelper<Dune::FieldMatrix<T, n, n>, T, + Dune::DiagonalMatrix<T, n>, + Dune::DiagonalMatrix<T, n>, false, false, false> { + typedef Dune::FieldMatrix<T, n, n> A; + typedef Dune::DiagonalMatrix<T, n> C; + typedef C D; + static void addProduct(A& a, const T& b, const C& c, const D& d) { + for (size_t i = 0; i < n; ++i) + a[i][i] += b * c.diagonal(i) * d.diagonal(i); + } + }; + + template <class T, int n, int m> + struct ProductHelper<Dune::FieldMatrix<T, n, m>, Dune::DiagonalMatrix<T, n>, + Dune::FieldMatrix<T, n, m>, false, false, false> { + typedef Dune::FieldMatrix<T, n, m> A; + typedef Dune::DiagonalMatrix<T, n> B; + typedef A C; + static void addProduct(A& a, const B& b, const C& c) { + for (size_t i = 0; i < n; ++i) + a[i].axpy(b.diagonal(i), c[i]); + } + }; + + template <class T, int n, int m> + struct ScaledProductHelper<Dune::FieldMatrix<T, n, m>, T, + Dune::DiagonalMatrix<T, n>, + Dune::FieldMatrix<T, n, m>, false, false, false> { + typedef Dune::FieldMatrix<T, n, m> A; + typedef Dune::DiagonalMatrix<T, n> C; + typedef A D; + static void addProduct(A& a, const T& b, const C& c, const D& d) { + for (size_t i = 0; i < n; ++i) + a[i].axpy(b * c.diagonal(i), d[i]); + } + }; + + template <class T, int n, int m> + struct ProductHelper<Dune::FieldMatrix<T, n, m>, Dune::FieldMatrix<T, n, m>, + Dune::DiagonalMatrix<T, m>, false, false, false> { + typedef Dune::FieldMatrix<T, n, m> A; + typedef Dune::DiagonalMatrix<T, m> C; + typedef A B; + + static void addProduct(A& a, const B& b, const C& c) { + for (size_t i = 0; i < n; ++i) + for (size_t j = 0; j < m; j++) + a[i][j] += c.diagonal(j) * b[i][j]; + } + }; + + template <class T, int n, int m> + struct ScaledProductHelper<Dune::FieldMatrix<T, n, m>, T, + Dune::FieldMatrix<T, n, m>, + Dune::DiagonalMatrix<T, m>, false, false, false> { + typedef Dune::FieldMatrix<T, n, m> A; + typedef Dune::DiagonalMatrix<T, m> D; + typedef A C; + + static void addProduct(A& a, const T& b, const C& c, const D& d) { + for (size_t i = 0; i < n; ++i) + for (size_t j = 0; j < m; j++) + a[i][j] += b * d.diagonal(j) * c[i][j]; + } + }; + + template <class T, int n> + struct ProductHelper<Dune::ScaledIdentityMatrix<T, n>, + Dune::ScaledIdentityMatrix<T, n>, + Dune::ScaledIdentityMatrix<T, n>, false, false, false> { + typedef Dune::ScaledIdentityMatrix<T, n> A; + typedef A B; + typedef B C; + + static void addProduct(A& a, const B& b, const C& c) { + a.scalar() += b.scalar() * c.scalar(); + } + }; + + template <class T, class Scalar, int n> + struct ScaledProductHelper<Dune::ScaledIdentityMatrix<T, n>, Scalar, + Dune::ScaledIdentityMatrix<T, n>, + Dune::ScaledIdentityMatrix<T, n>, false, false, + false> { + typedef Dune::ScaledIdentityMatrix<T, n> A; + typedef A C; + typedef C D; + + static void addProduct(A& a, const Scalar& b, const C& c, const D& d) { + a.scalar() += b * c.scalar() * d.scalar(); + } + }; + + /** \brief Specialization for b being a scalar type + */ + template <class A, class ScalarB, class C, bool AisScalar, bool CisScalar> + struct ProductHelper<A, ScalarB, C, AisScalar, true, CisScalar> { + typedef ScalarB B; + + template < + class ADummy = A, + std::enable_if_t<!MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const B& b, const C& c) { + a.axpy(b, c); + } + + template < + class ADummy = A, + std::enable_if_t<MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const B& b, const C& c) { + typename C::ConstRowIterator ci = c.begin(); + typename C::ConstRowIterator cEnd = c.end(); + for (; ci != cEnd; ++ci) { + typename C::ConstColIterator cik = c[ci.index()].begin(); + typename C::ConstColIterator ciEnd = c[ci.index()].end(); + for (; cik != ciEnd; ++cik) { + a[ci.index()][cik.index()] += b * (*cik); + } + } + } + }; + + template <class A, class Scalar, class ScalarB, class C, bool AisScalar, + bool CisScalar> + struct ScaledProductHelper<A, Scalar, ScalarB, C, AisScalar, true, + CisScalar> { + typedef ScalarB B; + + template < + class ADummy = A, + std::enable_if_t<!MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const Scalar& scalar, const B& b, const C& c) { + a.axpy(scalar * b, c); + } + + template < + class ADummy = A, + std::enable_if_t<MatrixTraits<ADummy>::isMatrix, int> SFINAE_Dummy = 0> + static void addProduct(A& a, const Scalar& scalar, const B& b, const C& c) { + typename C::ConstRowIterator ci = c.begin(); + typename C::ConstRowIterator cEnd = c.end(); + for (; ci != cEnd; ++ci) { + typename C::ConstColIterator cik = c[ci.index()].begin(); + typename C::ConstColIterator ciEnd = c[ci.index()].end(); + for (; cik != ciEnd; ++cik) { + a[ci.index()][cik.index()] += scalar * b * (*cik); + } + } + } + }; + + template <class ABlock, class ScalarB, class CBlock> + struct ProductHelper<Dune::BCRSMatrix<ABlock>, ScalarB, + Dune::BCRSMatrix<CBlock>, false, true, false> { + typedef Dune::BCRSMatrix<ABlock> A; + typedef ScalarB B; + typedef Dune::BCRSMatrix<CBlock> C; + + static void addProduct(A& a, const B& b, const C& c) { + // Workaround for the fact that Dune::BCRSMatrix assumes + // its blocks to have an axpy() implementation, yet + // Dune::DiagonalMatrix does not. + + // a.axpy(b, c); + + for (typename C::ConstIterator i = c.begin(); i != c.end(); ++i) { + const size_t iindex = i.index(); + for (typename C::row_type::ConstIterator j = i->begin(); j != i->end(); + ++j) + ProductHelper<typename A::block_type, B, typename C::block_type, + false, true, false>::addProduct(a[iindex][j.index()], b, + *j); + } + } + }; + + template <class ABlock, class Scalar, class ScalarB, class CBlock> + struct ScaledProductHelper<Dune::BCRSMatrix<ABlock>, Scalar, ScalarB, + Dune::BCRSMatrix<CBlock>, false, true, false> { + typedef Dune::BCRSMatrix<ABlock> A; + typedef ScalarB B; + typedef Dune::BCRSMatrix<CBlock> C; + + static void addProduct(A& a, const Scalar& scalar, const B& b, const C& c) { + // Workaround for the fact that Dune::BCRSMatrix assumes + // its blocks to have an axpy() implementation, yet + // Dune::DiagonalMatrix does not. + + // a.axpy(scalar*b, c); + + for (typename C::ConstIterator i = c.begin(); i != c.end(); ++i) { + const size_t iindex = i.index(); + for (typename C::row_type::ConstIterator j = i->begin(); j != i->end(); + ++j) + ProductHelper<typename A::block_type, B, typename C::block_type, + false, true, false>::addProduct(a[iindex][j.index()], + scalar * b, *j); + } + } + }; + + template <class T, int n, class ScalarB> + struct ProductHelper<Dune::ScaledIdentityMatrix<T, n>, ScalarB, + Dune::ScaledIdentityMatrix<T, n>, false, true, false> { + typedef Dune::ScaledIdentityMatrix<T, n> A; + typedef ScalarB B; + typedef Dune::ScaledIdentityMatrix<T, n> C; + + static void addProduct(A& a, const B& b, const C& c) { + a.scalar() += b * c.scalar(); + } + }; + + template <class T, int n, class Scalar, class ScalarB> + struct ScaledProductHelper<Dune::ScaledIdentityMatrix<T, n>, Scalar, ScalarB, + Dune::ScaledIdentityMatrix<T, n>, false, true, + false> { + typedef Dune::ScaledIdentityMatrix<T, n> A; + typedef ScalarB B; + typedef Dune::ScaledIdentityMatrix<T, n> C; + + static void addProduct(A& a, const Scalar& scalar, const B& b, const C& c) { + a.scalar() += scalar * b * c.scalar(); + } + }; + + template <class A, class B, class C> + struct ProductHelper<A, B, C, true, true, true> { + static void addProduct(A& a, const B& b, const C& c) { a += b * c; } + }; + + template <class A, class B, class C, class D> + struct ScaledProductHelper<A, B, C, D, true, true, true> { + static void addProduct(A& a, const B& b, const C& c, const D& d) { + a += b * c * d; + } + }; + + /** \brief Add a product to some matrix or vector + * + * This function computes a+=b*c. + * + * This function should tolerate all meaningful + * combinations of scalars, vectors, and matrices. + * + * a,b,c could be matrices with appropriate + * dimensions. But b can also always be a scalar + * represented by a 1-dim vector or a 1 by 1 matrix. + */ + template <class A, class B, class C> + void addProduct(A& a, const B& b, const C& c) { + ProductHelper<A, B, C, ScalarTraits<A>::isScalar, ScalarTraits<B>::isScalar, + ScalarTraits<C>::isScalar>::addProduct(a, b, c); + } + + /** \brief Subtract a product from some matrix or vector + * + * This function computes a-=b*c. + * + * This function should tolerate all meaningful + * combinations of scalars, vectors, and matrices. + * + * a,b,c could be matrices with appropriate + * dimensions. But b can also always be a scalar + * represented by a 1-dim vector or a 1 by 1 matrix. + */ + template <class A, class B, class C> + void subtractProduct(A& a, const B& b, const C& c) { + ScaledProductHelper<A, int, B, C, ScalarTraits<A>::isScalar, + ScalarTraits<B>::isScalar, + ScalarTraits<C>::isScalar>::addProduct(a, -1, b, c); + } + + /** \brief Add a scaled product to some matrix or vector + * + * This function computes a+=b*c*d. + * + * This function should tolerate all meaningful + * combinations of scalars, vectors, and matrices. + * + * a,c,d could be matrices with appropriate dimensions. But b must + * (currently) and c can also always be a scalar represented by a + * 1-dim vector or a 1 by 1 matrix. + */ + template <class A, class B, class C, class D> + typename std::enable_if<ScalarTraits<B>::isScalar, void>::type addProduct( + A& a, const B& b, const C& c, const D& d) { + ScaledProductHelper<A, B, C, D, ScalarTraits<A>::isScalar, + ScalarTraits<C>::isScalar, + ScalarTraits<D>::isScalar>::addProduct(a, b, c, d); + } + + /** \brief Subtract a scaled product from some matrix or vector + * + * This function computes a-=b*c*d. + * + * This function should tolerate all meaningful + * combinations of scalars, vectors, and matrices. + * + * a,c,d could be matrices with appropriate dimensions. But b must + * (currently) and c can also always be a scalar represented by a + * 1-dim vector or a 1 by 1 matrix. + */ + template <class A, class B, class C, class D> + typename std::enable_if<ScalarTraits<B>::isScalar, void>::type + subtractProduct(A& a, const B& b, const C& c, const D& d) { + ScaledProductHelper<A, B, C, D, ScalarTraits<A>::isScalar, + ScalarTraits<C>::isScalar, + ScalarTraits<D>::isScalar>::addProduct(a, -b, c, d); + } +} +} +#endif diff --git a/dune/matrix-vector/matrixtraits.hh b/dune/matrix-vector/matrixtraits.hh new file mode 100644 index 0000000..da72f65 --- /dev/null +++ b/dune/matrix-vector/matrixtraits.hh @@ -0,0 +1,55 @@ +#ifndef DUNE_MATRIX_VECTOR_MATRIXTRAITS_HH +#define DUNE_MATRIX_VECTOR_MATRIXTRAITS_HH + +#include <dune/common/diagonalmatrix.hh> +#include <dune/common/fmatrix.hh> +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/scaledidmatrix.hh> + +namespace Dune { + namespace MatrixVector { + + /** \brief Class to identify matrix types and extract information + * + * Specialize this class for all types that can be used like a matrix. + */ + template<class T> + struct MatrixTraits + { + enum { isMatrix=false }; + enum { rows=-1}; + enum { cols=-1}; + }; + + template<class T, int n, int m> + struct MatrixTraits<Dune::FieldMatrix<T,n,m> > + { + enum { isMatrix=true }; + enum { rows=n}; + enum { cols=m}; + }; + + template<class T, int n> + struct MatrixTraits<Dune::DiagonalMatrix<T,n> > + { + enum { isMatrix=true }; + enum { rows=n}; + enum { cols=n}; + }; + + template<class T, int n> + struct MatrixTraits<Dune::ScaledIdentityMatrix<T,n> > + { + enum { isMatrix=true }; + enum { rows=n}; + enum { cols=n}; + }; + + template<class T> + struct MatrixTraits<Dune::BCRSMatrix<T> > + { + enum { isMatrix=true }; + }; + } +} +#endif diff --git a/dune/matrix-vector/scalartraits.hh b/dune/matrix-vector/scalartraits.hh new file mode 100644 index 0000000..5fabfc1 --- /dev/null +++ b/dune/matrix-vector/scalartraits.hh @@ -0,0 +1,44 @@ +#ifndef DUNE_MATRIX_VECTOR_SCALARTRAITS_HH +#define DUNE_MATRIX_VECTOR_SCALARTRAITS_HH + +#include <dune/common/diagonalmatrix.hh> +#include <dune/common/fmatrix.hh> +#include <dune/istl/bcrsmatrix.hh> +#include <dune/istl/scaledidmatrix.hh> + +namespace Dune { +namespace MatrixVector { + /** \brief Class to identify scalar types + * + * Specialize this class for all types that can be used + * like scalar quantities. + */ + template <class T> + struct ScalarTraits { + enum { + isScalar = (std::is_scalar<T>::value and not std::is_pointer<T>::value) + }; + }; + + template <class T> + struct ScalarTraits<Dune::FieldVector<T, 1>> { + enum { isScalar = true }; + }; + + template <class T> + struct ScalarTraits<Dune::FieldMatrix<T, 1, 1>> { + enum { isScalar = true }; + }; + + template <class T> + struct ScalarTraits<Dune::DiagonalMatrix<T, 1>> { + enum { isScalar = true }; + }; + + template <class T> + struct ScalarTraits<Dune::ScaledIdentityMatrix<T, 1>> { + enum { isScalar = true }; + }; +} +} +#endif -- GitLab