diff --git a/src/amdis/common/FieldMatVec.hpp b/src/amdis/common/FieldMatVec.hpp index 6a316262b4e16a8e517d4989c385dd73190378fc..a7d61c19836310ef5d7b737a9215b1ce545b81ad 100644 --- a/src/amdis/common/FieldMatVec.hpp +++ b/src/amdis/common/FieldMatVec.hpp @@ -23,22 +23,168 @@ namespace std namespace Dune { - // some arithmetic operations with FieldVector + namespace MatVec + { + /// Traits to detect fixed size containers like FieldVector and FieldMatrix + /// @{ + template <class T> + struct IsMatrix : std::false_type {}; + + template <class T, int M, int N> + struct IsMatrix<FieldMatrix<T,M,N>> : std::true_type {}; + + template <class T, int N> + struct IsMatrix<DiagonalMatrix<T,N>> : std::true_type {}; + + + template <class T> + struct IsVector : std::false_type {}; + + template <class T, int N> + struct IsVector<FieldVector<T,N>> : std::true_type {}; + + + template <class T> + struct IsMatVec + : std::integral_constant<bool, IsMatrix<T>::value || IsVector<T>::value> {}; + /// @} + + /// Convert the field_Type of container to type S + /// @{ + template <class A, class S> + struct MakeMatVec + { + using type = A; + }; + + template <class T, int M, int N, class S> + struct MakeMatVec<FieldMatrix<T,M,N>,S> + { + using type = FieldMatrix<S,M,N>; + }; + + template <class T, int N, class S> + struct MakeMatVec<DiagonalMatrix<T,N>,S> + { + using type = DiagonalMatrix<S,N>; + }; + + template <class T, int N, class S> + struct MakeMatVec<FieldVector<T,N>,S> + { + using type = FieldVector<S,N>; + }; + /// @} + + /// Convert pseudo-scalar to real scalar type + /// @{ + template <class T> + decltype(auto) simplify(T&& t) + { + return std::forward<T>(t); + } + + template <class T> + T simplify(FieldVector<T,1> const& t) + { + return t[0]; + } + + template <class T> + T simplify(FieldMatrix<T,1,1> const& t) + { + return t[0][0]; + } + + template <class T> + T simplify(DiagonalMatrix<T,1> const& t) + { + return t.diagonal(0); + } + /// @} + + // returns -a + template <class A> + auto negate(A const& a); + + // returns a+b + template <class A, class B> + auto plus(A a, B const& b) + { + return a += b; + } + + // returns a-b + template <class A, class B> + auto minus(A a, B const& b) + { + return a -= b; + } + + // returns a*b + template <class A, class B, + std::enable_if_t<IsNumber<A>::value || IsNumber<B>::value, int> = 0> + auto multiplies(A const& a, B const& b); + + template <class T, int N, class S> + auto multiplies(FieldVector<T,N> const& a, FieldVector<S,N> const& b); + + template <class Mat, class Vec, + std::enable_if_t<IsMatrix<Mat>::value && IsVector<Vec>::value, int> = 0> + auto multiplies(Mat const& mat, Vec const& vec); + + template <class Vec, class Mat, + std::enable_if_t<IsVector<Vec>::value && IsMatrix<Mat>::value, int> = 0> + auto multiplies(Vec const& vec, Mat const& mat); + + template <class T, int L, int M, int N, class S> + auto multiplies(FieldMatrix<T,L,M> const& a, FieldMatrix<S,M,N> const& b); + + // return a/b + template <class A, class B> + auto divides(A a, B const& b) + { + return a /= b; + } + + } // end namespace MatVec + + // some arithmetic operations with FieldVector and FieldMatrix + + template <class A, + std::enable_if_t<MatVec::IsMatVec<A>::value, int> = 0> + auto operator-(A const& a) + { + return MatVec::negate(MatVec::simplify(a)); + } - template <class T, int N> - FieldVector<T,N> operator-(FieldVector<T,N> v); + template <class A, class B, + std::enable_if_t<MatVec::IsMatVec<A>::value || MatVec::IsMatVec<B>::value, int> = 0> + auto operator+(A const& a, B const& b) + { + return MatVec::plus(MatVec::simplify(a), MatVec::simplify(b)); + } - template <class T, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int> = 0> - FieldVector<T,N> operator*(FieldVector<T,N> v, S factor); + template <class A, class B, + std::enable_if_t<MatVec::IsMatVec<A>::value || MatVec::IsMatVec<B>::value, int> = 0> + auto operator-(A const& a, B const& b) + { + return MatVec::minus(MatVec::simplify(a), MatVec::simplify(b)); + } - template <class T, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int> = 0> - FieldVector<T,N> operator*(S factor, FieldVector<T,N> v); + template <class A, class B, + std::enable_if_t<MatVec::IsMatVec<A>::value || MatVec::IsMatVec<B>::value, int> = 0> + auto operator*(A const& a, B const& b) + { + return MatVec::multiplies(MatVec::simplify(a), MatVec::simplify(b)); + } - template <class T, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int> = 0> - FieldVector<T,N> operator/(FieldVector<T,N> v, S factor); + template <class A, class B, + std::enable_if_t<MatVec::IsMatVec<A>::value || MatVec::IsMatVec<B>::value, int> = 0> + auto operator/(A const& a, B const& b) + { + return MatVec::divides(MatVec::simplify(a), MatVec::simplify(b)); + } // ---------------------------------------------------------------------------- @@ -197,38 +343,8 @@ namespace Dune template <class T, int M, int N> FieldMatrix<T,N,M> trans(FieldMatrix<T, M, N> const& A); - template <class T, int M, int N> - FieldMatrix<T,M,N> operator-(FieldMatrix<T, M, N> A); - - - template <class T, int M, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int> = 0> - FieldMatrix<T,M,N> operator*(S scalar, FieldMatrix<T, M, N> A); - - template <class T, int M, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int> = 0> - FieldMatrix<T,M,N> operator*(FieldMatrix<T, M, N> A, S scalar); - - template <class T, int M, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int> = 0> - FieldMatrix<T,M,N> operator/(FieldMatrix<T, M, N> A, S scalar); - - - template <class T, int M, int N> - FieldMatrix<T,M,N> operator+(FieldMatrix<T, M, N> A, FieldMatrix<T, M, N> const& B); - - template <class T, int M, int N> - FieldMatrix<T,M,N> operator-(FieldMatrix<T, M, N> A, FieldMatrix<T, M, N> const& B); - - - template <class T, int N, int M> - FieldVector<T,N> operator*(FieldMatrix<T,N,M> const& mat, FieldVector<T,M> const& vec); - // ----------------------------------------------------------------------------- - template <class T, int M, int N, int L> - FieldMatrix<T,M,N> multiplies(FieldMatrix<T, M, L> const& A, FieldMatrix<T, L, N> const& B); - template <class T, int M, int N, int L> FieldMatrix<T,M,N> multiplies_AtB(FieldMatrix<T, L, M> const& A, FieldMatrix<T, N, L> const& B); @@ -243,20 +359,6 @@ namespace Dune // ----------------------------------------------------------------------------- - template <class T> - T operator*(FieldVector<T, 1> lhs, FieldVector<T, 1> rhs); - - template <class T> - T operator*(FieldMatrix<T, 1, 1> lhs, FieldMatrix<T, 1, 1> rhs); - - template <class T> - T operator*(FieldVector<T, 1> lhs, FieldMatrix<T, 1, 1> rhs); - - template <class T> - T operator*(FieldMatrix<T, 1, 1> lhs, FieldVector<T, 1> rhs); - - // ----------------------------------------------------------------------------- - template <class T, int N> T const& at(FieldMatrix<T,N,1> const& vec, std::size_t i); diff --git a/src/amdis/common/FieldMatVec.inc.hpp b/src/amdis/common/FieldMatVec.inc.hpp index cadb8d3a551bc7a2d6f61d281880585f7b64f964..8e57a3ea506ba0386e70145be9426d01d8ca3604 100644 --- a/src/amdis/common/FieldMatVec.inc.hpp +++ b/src/amdis/common/FieldMatVec.inc.hpp @@ -11,34 +11,81 @@ namespace Dune { -// some arithmetic operations with FieldVector +namespace MatVec { -template <class T, int N> -FieldVector<T,N> operator-(FieldVector<T,N> v) -{ - return v *= -1; -} + template <class A> + auto negate(A const& a) + { + return multiplies(a, -1); + } -template <class T, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int>> -FieldVector<T,N> operator*(FieldVector<T,N> v, S factor) -{ - return v *= factor; -} + template <class A, class B, + std::enable_if_t<IsNumber<A>::value || IsNumber<B>::value, int>> + auto multiplies(A const& a, B const& b) + { + using T = std::common_type_t<typename FieldTraits<A>::field_type, typename FieldTraits<B>::field_type>; +#if AMDIS_HAS_CXX_CONSTEXPR_IF + if constexpr(IsNumber<A>::value) { + typename MakeMatVec<B,T>::type b_{b}; + return b_ *= a; + } else { + typename MakeMatVec<A,T>::type a_{a}; + return a_ *= b; + } +#else + return Hybrid::ifElse(IsNumber<A>{}, + [&](auto id) { typename MakeMatVec<B,T>::type b_{b}; return id(b_) *= id(a); }, + [&](auto id) { typename MakeMatVec<A,T>::type a_{a}; return id(a_) *= id(b); }); +#endif + } -template <class T, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int>> -FieldVector<T,N> operator*(S factor, FieldVector<T,N> v) -{ - return v *= factor; -} + template <class T, int N, class S> + auto multiplies(FieldVector<T,N> const& a, FieldVector<S,N> const& b) + { + return a.dot(b); + } -template <class T, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int>> -FieldVector<T,N> operator/(FieldVector<T,N> v, S factor) -{ - return v /= factor; -} + + template <class Mat, class Vec, + std::enable_if_t<IsMatrix<Mat>::value && IsVector<Vec>::value, int>> + auto multiplies(Mat const& mat, Vec const& vec) + { + static_assert(Mat::cols == Vec::dimension, ""); + using T = std::common_type_t<typename FieldTraits<Vec>::field_type, typename FieldTraits<Mat>::field_type>; + FieldVector<T,Mat::rows> y; + mat.mv(vec, y); + return y; + } + + + template <class Vec, class Mat, + std::enable_if_t<IsVector<Vec>::value && IsMatrix<Mat>::value, int>> + auto multiplies(Vec const& vec, Mat const& mat) + { + static_assert(Mat::rows == Vec::dimension, ""); + using T = std::common_type_t<typename FieldTraits<Vec>::field_type, typename FieldTraits<Mat>::field_type>; + FieldVector<T,Mat::cols> y; + mat.mtv(vec, y); + return y; + } + + + template <class T, int L, int M, int N, class S> + auto multiplies(FieldMatrix<T,L,M> const& a, FieldMatrix<S,M,N> const& b) + { + FieldMatrix<std::common_type_t<T,S>,L,N> C; + + for (int i = 0; i < L; ++i) { + for (int j = 0; j < N; ++j) { + C[i][j] = 0; + for (int k = 0; k < M; ++k) + C[i][j] += a[i][k]*b[k][j]; + } + } + return C; + } + +} // end namespace MatVec // ---------------------------------------------------------------------------- @@ -349,57 +396,6 @@ FieldMatrix<T,N,M> trans(FieldMatrix<T, M, N> const& A) return At; } -template <class T, int M, int N> -FieldMatrix<T,M,N> operator-(FieldMatrix<T,M,N> A) -{ - return A *= -1; -} - -template <class T, int M, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int>> -FieldMatrix<T,M,N> operator*(S scalar, FieldMatrix<T, M, N> A) -{ - return A *= scalar; -} - -template <class T, int M, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int>> -FieldMatrix<T,M,N> operator*(FieldMatrix<T, M, N> A, S scalar) -{ - return A *= scalar; -} - -template <class T, int M, int N, class S, - std::enable_if_t<std::is_convertible<S,T>::value, int>> -FieldMatrix<T,M,N> operator/(FieldMatrix<T, M, N> A, S scalar) -{ - return A /= scalar; -} - -template <class T, int M, int N> -FieldMatrix<T,M,N> operator+(FieldMatrix<T, M, N> A, FieldMatrix<T, M, N> const& B) -{ - return A += B; -} - -template <class T, int M, int N> -FieldMatrix<T,M,N> operator-(FieldMatrix<T, M, N> A, FieldMatrix<T, M, N> const& B) -{ - return A -= B; -} - - -template <class T, int N, int M> -FieldVector<T,N> operator*(FieldMatrix<T,N,M> const& mat, FieldVector<T,M> const& vec) -{ - return Dune::FMatrixHelp::mult(mat, vec); -} - -template <class T, int M, int N, int L> -FieldMatrix<T,M,N> multiplies(FieldMatrix<T, M, L> const& A, FieldMatrix<T, L, N> const& B) -{ - return A.rightmultiplyany(B); -} template <class T, int M, int N, int L> FieldMatrix<T,M,N> multiplies_AtB(FieldMatrix<T, L, M> const& A, FieldMatrix<T, N, L> const& B) @@ -447,32 +443,6 @@ FieldMatrix<T,M,N>& multiplies_ABt(FieldMatrix<T, M, N> const& A, DiagonalMatri return C; } - -template <class T> -T operator*(FieldVector<T,1> lhs, FieldVector<T,1> rhs) -{ - return lhs[0] * rhs[0]; -} - -template <class T> -T operator*(FieldMatrix<T,1,1> lhs, FieldMatrix<T,1,1> rhs) -{ - return lhs[0][0] * rhs[0][0]; -} - -template <class T> -T operator*(FieldVector<T,1> lhs, FieldMatrix<T,1,1> rhs) -{ - return lhs[0] * rhs[0][0]; -} - -template <class T> -T operator*(FieldMatrix<T,1,1> lhs, FieldVector<T,1> rhs) -{ - return lhs[0][0] * rhs[0]; -} - - template <class T, int N> T const& at(FieldMatrix<T,N,1> const& vec, std::size_t i) { diff --git a/test/FieldMatVecTest.cpp b/test/FieldMatVecTest.cpp index 9f3768389b75c2da00afeec4c0e4b4d914d6cf57..53ea56a4695e1e0f73ed1f46ae4f459fe49efe0e 100644 --- a/test/FieldMatVecTest.cpp +++ b/test/FieldMatVecTest.cpp @@ -101,7 +101,7 @@ void test2() AMDIS_TEST_EQ( det(A), 1.0 ); AMDIS_TEST_EQ( det(B), 0.0 ); - AMDIS_TEST_EQ( det(multiplies(C,D)), det(C)*det(D) ); + AMDIS_TEST_EQ( det(C*D), det(C)*det(D) ); AMDIS_TEST_EQ( det(trans(C)), det(C) ); AMDIS_TEST_EQ( det(2.0*D), Math::pow<3>(2.0)*det(D) ); @@ -201,6 +201,15 @@ void test3() AMDIS_TEST_EQ( vi1*mi1, 1 ); AMDIS_TEST_EQ( mi1*mi1, 1 ); AMDIS_TEST_EQ( mi1*vi1, 1 ); + + AMDIS_TEST_EQ( vd1*vi1, 1.0 ); + AMDIS_TEST_EQ( vd1*mi1, 1.0 ); + AMDIS_TEST_EQ( vi1*vd1, 1.0 ); + AMDIS_TEST_EQ( vi1*md1, 1.0 ); + AMDIS_TEST_EQ( md1*vi1, 1.0 ); + AMDIS_TEST_EQ( md1*mi1, 1.0 ); + AMDIS_TEST_EQ( mi1*vd1, 1.0 ); + AMDIS_TEST_EQ( mi1*md1, 1.0 ); }