dune-common  2.11
transpose.hh
Go to the documentation of this file.
1 // -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=4 sw=2 sts=2:
3 // SPDX-FileCopyrightInfo: Copyright © DUNE Project contributors, see file LICENSE.md in module root
4 // SPDX-License-Identifier: LicenseRef-GPL-2.0-only-with-DUNE-exception
5 #ifndef DUNE_COMMON_TRANSPOSE_HH
6 #define DUNE_COMMON_TRANSPOSE_HH
7 
8 #include <cstddef>
9 #include <functional>
10 
13 #include <dune/common/fmatrix.hh>
16 #include <dune/common/dynmatrix.hh>
18 
19 namespace Dune {
20 
21 namespace Impl {
22 
23 
24 
25  template<class M, bool = IsStaticSizeMatrix<M>::value>
26  struct TransposedDenseMatrixTraits
27  {
28  using type = Dune::FieldMatrix<typename FieldTraits<M>::field_type, M::cols, M::rows>;
29  };
30 
31  template<class M>
32  struct TransposedDenseMatrixTraits<M, false>
33  {
35  };
36 
37  template<class M>
38  using TransposedDenseMatrixTraits_t = typename TransposedDenseMatrixTraits<M>::type;
39 
40 
41 
42  // CRTP mixin class to provide the static part of the interface,
43  // namely enums rows and cols.
44  template<class WM, bool staticSize = IsStaticSizeMatrix<WM>::value>
45  class TransposedMatrixWrapperMixin {};
46 
47  template<class WM>
48  class TransposedMatrixWrapperMixin<WM, true>
49  {
50  public:
51 
53  constexpr static int rows = WM::cols;
55  constexpr static int cols = WM::rows;
56  };
57 
58 
59 
60  template<class M>
61  class TransposedMatrixWrapper;
62 
63 } // namespace Impl
64 
65 // Specialization of FieldTraits needs to be in namespace Dune::
66 template<class M>
67 struct FieldTraits< Impl::TransposedMatrixWrapper<M> >
68 {
69  using field_type = typename FieldTraits<ResolveRef_t<M>>::field_type;
70  using real_type = typename FieldTraits<ResolveRef_t<M>>::real_type;
71 };
72 
73 namespace Impl {
74 
75  // Specialize the traits `IsDenseMatrix` as true only if the wrapped matrix
76  // is a dense matrix.
77  template<class M>
78  struct IsDenseMatrix< TransposedMatrixWrapper<M> > :
79  public IsDenseMatrix<ResolveRef_t<M>> {};
80 
81  // Wrapper representing the transposed of a matrix.
82  // Creating the wrapper does not compute anything
83  // but only serves for tagging the wrapped matrix
84  // for transposition. This class will store the matrix
85  // of type `Matrix` by value. To support reference-semantic,
86  // it supports using Matrix=std::reference_wrapper<OriginalMatrixType>.
87  template<class Matrix>
88  class TransposedMatrixWrapper :
89  public TransposedMatrixWrapperMixin<ResolveRef_t<Matrix>>
90  {
91  constexpr static bool hasStaticSize = IsStaticSizeMatrix<ResolveRef_t<Matrix>>::value;
92  public:
93  using WrappedMatrix = ResolveRef_t<Matrix>;
94 
95  const WrappedMatrix& wrappedMatrix() const {
96  return resolveRef(matrix_);
97  }
98 
99 
100  using value_type = typename WrappedMatrix::value_type;
101  using field_type = typename FieldTraits<WrappedMatrix>::field_type;
102  using size_type = typename WrappedMatrix::size_type;
103 
104  TransposedMatrixWrapper(Matrix&& matrix) : matrix_(std::move(matrix)) {}
105  TransposedMatrixWrapper(const Matrix& matrix) : matrix_(matrix) {}
106 
107  private:
108 
109  // helper proxy type to access elements by chained `operator[][]`
110  struct AccessProxy
111  {
112  const WrappedMatrix& wrappedMatrix_;
113  size_type i_;
114 
115  decltype(auto) operator[] (size_type j) const
116  {
117  DUNE_ASSERT_BOUNDS(j < wrappedMatrix_.N());
118  return wrappedMatrix_[j][i_];
119  }
120  };
121 
122  public:
123 
130  auto operator[] (size_type i) const requires(Impl::IsDenseMatrix_v<WrappedMatrix>)
131  {
132  DUNE_ASSERT_BOUNDS(i < wrappedMatrix().M());
133  return AccessProxy{wrappedMatrix(),i};
134  }
135 
136  template<class MatrixA,
137  std::enable_if_t<
138  ((not Impl::IsFieldMatrix<MatrixA>::value) or (not hasStaticSize))
139  and Impl::IsDenseMatrix_v<MatrixA>, int> = 0>
140  friend auto operator* (const MatrixA& matrixA, const TransposedMatrixWrapper& matrixB)
141  {
142  using FieldA = typename FieldTraits<MatrixA>::field_type;
143  using FieldB = typename FieldTraits<TransposedMatrixWrapper>::field_type;
144  using Field = typename PromotionTraits<FieldA, FieldB>::PromotedType;
145 
146  // We exploit that the rows of AB^T are the columns of (AB^T)^T = BA^T.
147  // Hence we get the row-vectors of AB^T by multiplying B to the row-vectors
148  // of A.
149  if constexpr(IsStaticSizeMatrix_v<MatrixA> and IsStaticSizeMatrix_v<WrappedMatrix>)
150  {
151  FieldMatrix<Field, MatrixA::rows, WrappedMatrix::rows> result;
152  for (std::size_t j=0; j<MatrixA::rows; ++j)
153  matrixB.wrappedMatrix().mv(matrixA[j], result[j]);
154  return result;
155  }
156  else
157  {
158  DynamicMatrix<Field> result(matrixA.N(), matrixB.wrappedMatrix().N());
159  for (std::size_t j=0; j<matrixA.N(); ++j)
160  matrixB.wrappedMatrix().mv(matrixA[j], result[j]);
161  return result;
162  }
163  }
164 
167  constexpr size_type N () const
168  {
169  return wrappedMatrix().M();
170  }
171 
174  constexpr size_type M () const
175  {
176  return wrappedMatrix().N();
177  }
178 
179  template<class X, class Y>
180  void mv (const X& x, Y& y) const
181  {
182  wrappedMatrix().mtv(x,y);
183  }
184 
185  template<class X, class Y>
186  void mtv (const X& x, Y& y) const
187  {
188  wrappedMatrix().mv(x,y);
189  }
190 
191  // Return a classical representation of the matrix.
192  // Since we do not know the internals of the wrapped
193  // matrix, this will always be a dense matrix. Depending
194  // on whether the matrix has static size or not, this
195  // will be either a FieldMatrix or a DynamicMatrix.
196  TransposedDenseMatrixTraits_t<WrappedMatrix> asDense() const
197  {
198  TransposedDenseMatrixTraits_t<WrappedMatrix> MT;
199  if constexpr(not IsStaticSizeMatrix<WrappedMatrix>::value)
200  {
201  MT.resize(wrappedMatrix().M(), wrappedMatrix().N(), 0);
202  }
203  for(auto&& [M_i, i] : Dune::sparseRange(wrappedMatrix()))
204  for(auto&& [M_ij, j] : Dune::sparseRange(M_i))
205  MT[j][i] = M_ij;
206  return MT;
207  }
208 
209  private:
210 
211  Matrix matrix_;
212  };
213 
214  template<class M>
215  using MemberFunctionTransposedConcept = std::void_t<decltype(std::declval<M>().transposed())>;
216 
217  template<class M>
218  struct HasMemberFunctionTransposed : public Dune::Std::is_detected<MemberFunctionTransposedConcept, M> {};
219 
220 } // namespace Impl
221 
222 
223 
232 template<class Matrix,
233  std::enable_if_t<Impl::HasMemberFunctionTransposed<Matrix>::value, int> = 0>
234 auto transpose(const Matrix& matrix) {
235  return matrix.transposed();
236 }
237 
238 
239 
261 template<class Matrix,
262  std::enable_if_t<not Impl::HasMemberFunctionTransposed<std::decay_t<Matrix>>::value, int> = 0>
263 auto transpose(Matrix&& matrix) {
264  return Impl::TransposedMatrixWrapper(std::forward<Matrix>(matrix));
265 }
266 
267 
268 
295 template<class Matrix>
296 auto transpose(const std::reference_wrapper<Matrix>& matrix) {
297  return Impl::TransposedMatrixWrapper(matrix);
298 }
299 
300 
301 
311 template<class Matrix>
312 auto transposedView(const Matrix& matrix) {
313  return transpose(std::cref(matrix));
314 }
315 
316 
317 
318 
319 
320 } // namespace Dune
321 
322 #endif // DUNE_COMMON_TRANSPOSE_HH
typename detected_or< nonesuch, Op, Args... >::value_t is_detected
Detects whether Op<Args...> is valid.
Definition: type_traits.hh:141
auto transposedView(const Matrix &matrix)
Create a view modelling the transposed matrix.
Definition: transpose.hh:312
Implements a matrix constructed from a given type representing a field and compile-time given number ...
auto transpose(const Matrix &matrix)
Return the transposed of the given matrix.
Definition: transpose.hh:234
decltype(std::declval< T1 >()+std::declval< T2 >()) typedef PromotedType
Definition: promotiontraits.hh:28
requires(((std::is_integral_v< I > or Dune::IsIntegralConstant< I >::value) &&...)) HybridMultiIndex(I... i) -> HybridMultiIndex< decltype(Impl::castToHybridSizeT(i))... >
auto sparseRange(Range &&range)
Allow structured-binding for-loops for sparse iterators.
Definition: rangeutilities.hh:716
constexpr T & resolveRef(T &gf) noexcept
Helper function to resolve std::reference_wrapper.
Definition: referencehelper.hh:47
A dense n x m matrix.
Definition: densematrix.hh:39
#define DUNE_ASSERT_BOUNDS(cond)
If DUNE_CHECK_BOUNDS is defined: check if condition cond holds; otherwise, do nothing.
Definition: boundschecking.hh:30
I i
Definition: hybridmultiindex.hh:328
T real_type
export the type representing the real type of the field
Definition: ftraits.hh:30
Macro for wrapping boundary checks.
Dune namespace
Definition: alignedallocator.hh:12
This file implements a dense matrix with dynamic numbers of rows and columns.
Construct a matrix with a dynamic size.
Definition: dynmatrix.hh:31
Compute type of the result of an arithmetic operation involving two different number types...
T field_type
export the type representing the field
Definition: ftraits.hh:28
STL namespace.