From b0feb4264935424780520a2f8536269fd1ae6886 Mon Sep 17 00:00:00 2001
From: Elias Pipping <elias.pipping@fu-berlin.de>
Date: Mon, 25 Jul 2016 15:18:55 +0200
Subject: [PATCH] Incorporate matrix transforms from StaticMatrix

---
 dune/matrix-vector/CMakeLists.txt     |   1 +
 dune/matrix-vector/transformmatrix.hh | 358 ++++++++++++++++++++++++++
 2 files changed, 359 insertions(+)
 create mode 100644 dune/matrix-vector/transformmatrix.hh

diff --git a/dune/matrix-vector/CMakeLists.txt b/dune/matrix-vector/CMakeLists.txt
index c3d9227..4d090e0 100644
--- a/dune/matrix-vector/CMakeLists.txt
+++ b/dune/matrix-vector/CMakeLists.txt
@@ -13,4 +13,5 @@ install(FILES
   singlenonzerocolumnmatrix.hh
   singlenonzerorowmatrix.hh
   tranpose.hh
+  transformmatrix.hh
   DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dune/matrix-vector)
\ No newline at end of file
diff --git a/dune/matrix-vector/transformmatrix.hh b/dune/matrix-vector/transformmatrix.hh
new file mode 100644
index 0000000..3ce403e
--- /dev/null
+++ b/dune/matrix-vector/transformmatrix.hh
@@ -0,0 +1,358 @@
+#ifndef DUNE_MATRIX_VECTOR_ADDTRANSFORMED_HH
+#define DUNE_MATRIX_VECTOR_ADDTRANSFORMED_HH
+
+#include <dune/common/diagonalmatrix.hh>
+#include <dune/common/fmatrix.hh>
+#include <dune/istl/matrixindexset.hh>
+#include <dune/istl/scaledidmatrix.hh>
+
+#include "axpy.hh"
+#include "scalartraits.hh"
+
+namespace Dune {
+namespace MatrixVector {
+
+  // add transformed matrix A += T1^t*B*T2
+  // ******************************************************
+  template <class MatrixA, class MatrixB, class TransformationMatrix,
+            bool AisScalar, bool BisScalar, bool TisScalar>
+  struct TransformMatrixHelper {
+    static void addTransformedMatrix(MatrixA& A, const TransformationMatrix& T1,
+                                     const MatrixB& B,
+                                     const TransformationMatrix& T2) {
+      for (size_t i = 0; i < A.N(); ++i) {
+        typename MatrixA::row_type::Iterator jIt = A[i].begin();
+        typename MatrixA::row_type::Iterator jEnd = A[i].end();
+        for (; jIt != jEnd; ++jIt) {
+          for (size_t k = 0; k < B.N(); ++k) {
+            if (T1.exists(k, i)) {
+              typename MatrixB::row_type::ConstIterator lIt = B[k].begin();
+              typename MatrixB::row_type::ConstIterator lEnd = B[k].end();
+              for (; lIt != lEnd; ++lIt)
+                if (T2.exists(lIt.index(), jIt.index()))
+                  *jIt += T1[k][i] * (*lIt) * T2[lIt.index()][jIt.index()];
+            }
+          }
+        }
+      }
+    }
+
+    // static void transformMatrix(MatrixA& A, const
+    // TransformationMatrix& T1, const MatrixB& B, const
+    // TransformationMatrix& T2)
+    // {
+    //     A = 0.0;
+    //     for (int k=0; k<B.N(); ++k)
+    //     {
+    //         typename MatrixB::row_type::ConstIterator
+    //         lIt=B[k].begin();
+    //         typename MatrixB::row_type::ConstIterator
+    //         lEnd=B[k].end();
+    //         for (; lIt!=lEnd; ++lIt)
+    //         {
+    //             typename
+    //             TransformationMatrix::row_type::ConstIterator
+    //             iIt=T1[k].begin();
+    //             typename
+    //             TransformationMatrix::row_type::ConstIterator
+    //             iEnd=T1[k].end();
+    //             for (; iIt!=iEnd; ++iIt)
+    //             {
+    //                 typename
+    //                 TransformationMatrix::row_type::ConstIterator
+    //                 jIt=T2[lIt.index()].begin();
+    //                 typename
+    //                 TransformationMatrix::row_type::ConstIterator
+    //                 jEnd=T2[lIt.index()].end();
+    //                 for (; jIt!=jEnd; ++jIt)
+    //                     A[iIt.index()][jIt.index()] = (*iIt) *
+    //                     (*lIt) * (*jIt);
+    //             }
+    //         }
+    //     }
+    // }
+  };
+
+  template <class K1, class K2, class K3, int n, int m>
+  struct TransformMatrixHelper<
+      Dune::FieldMatrix<K1, m, m>, Dune::FieldMatrix<K3, n, n>,
+      Dune::FieldMatrix<K2, n, m>, false, false, false> {
+    typedef Dune::FieldMatrix<K1, m, m> MatrixA;
+    typedef Dune::FieldMatrix<K3, n, n> MatrixB;
+    typedef Dune::FieldMatrix<K2, n, m> TransformationMatrix;
+
+    static void addTransformedMatrix(MatrixA& A, const TransformationMatrix& T1,
+                                     const MatrixB& B,
+                                     const TransformationMatrix& T2) {
+      Dune::FieldMatrix<K1, m, n> T1transposedB;
+      T1transposedB = 0;
+      for (size_t i = 0; i < MatrixA::rows; ++i) {
+        for (size_t k = 0; k < MatrixB::rows; ++k) {
+          if (T1[k][i] != 0)
+            for (size_t l = 0; l < MatrixB::cols; ++l)
+              T1transposedB[i][l] += T1[k][i] * B[k][l];
+        }
+      }
+      for (size_t k = 0; k < TransformationMatrix::rows; ++k) {
+        for (size_t l = 0; l < TransformationMatrix::cols; ++l) {
+          if (T2[k][l] != 0)
+            for (size_t i = 0; i < MatrixA::rows; ++i)
+              A[i][l] += T1transposedB[i][k] * T2[k][l];
+        }
+      }
+    }
+
+    // static void transformMatrix(MatrixA& A, const
+    // TransformationMatrix& T1, const MatrixB& B, const
+    // TransformationMatrix& T2)
+    // {
+    //     A = 0.0;
+    //     for (int k=0; k<B.N(); ++k)
+    //         for (int l=0; l<B.M(); ++l)
+    //             for (int i=0; i<T1.M(); ++i)
+    //                 for (int j=0; j<T2.M(); ++j)
+    //                     A[i][j] = T1[k][i] * B[k][l] * T2[l][j];
+    // }
+  };
+
+  template <class MatrixA, class MatrixB, class ScalarTransform, bool AisScalar,
+            bool BisScalar>
+  struct TransformMatrixHelper<MatrixA, MatrixB, ScalarTransform, AisScalar,
+                               BisScalar, true> {
+    static void addTransformedMatrix(MatrixA& A, const ScalarTransform& T1,
+                                     const MatrixB& B,
+                                     const ScalarTransform& T2) {
+      addProduct(A, T1 * T2, B);
+    }
+  };
+
+  template <class MatrixA, class ScalarB, class TransformationMatrix,
+            bool AisScalar, bool TisScalar>
+  struct TransformMatrixHelper<MatrixA, ScalarB, TransformationMatrix,
+                               AisScalar, true, TisScalar> {
+    static void addTransformedMatrix(MatrixA& A, const TransformationMatrix& T1,
+                                     const ScalarB& B,
+                                     const TransformationMatrix& T2) {
+      for (size_t k = 0; k < TransformationMatrix::rows; ++k) {
+        typename TransformationMatrix::ConstColIterator Skj = T2[k].begin();
+        typename TransformationMatrix::ConstColIterator SkEnd = T2[k].end();
+        for (; Skj != SkEnd; ++Skj) {
+          typename TransformationMatrix::ConstColIterator Tki = T1[k].begin();
+          typename TransformationMatrix::ConstColIterator TkEnd = T1[k].end();
+          for (; Tki != TkEnd; Tki++)
+            if (A.exists(Tki.index(), Skj.index()))
+              A[Tki.index()][Skj.index()] += (*Tki) * B * (*Skj);
+        }
+      }
+    }
+  };
+
+  template <class FieldType, int n, class ScalarB, class TransformationMatrix,
+            bool AisScalar, bool TisScalar>
+  struct TransformMatrixHelper<Dune::ScaledIdentityMatrix<FieldType, n>,
+                               ScalarB, TransformationMatrix, AisScalar, true,
+                               TisScalar> {
+    typedef Dune::ScaledIdentityMatrix<FieldType, n> MatrixA;
+    static void addTransformedMatrix(MatrixA& A, const TransformationMatrix& T1,
+                                     const ScalarB& B,
+                                     const TransformationMatrix& T2) {
+      TransformMatrixHelper<FieldType, ScalarB,
+                            typename TransformationMatrix::field_type, true,
+                            true, true>::addTransformedMatrix(A.scalar(),
+                                                              T1.scalar(), B,
+                                                              T2.scalar());
+    }
+  };
+
+  template <class ScalarA, class ScalarB, class ScalarTransform>
+  struct TransformMatrixHelper<ScalarA, ScalarB, ScalarTransform, true, true,
+                               true> {
+    static void addTransformedMatrix(ScalarA& A, const ScalarTransform& T1,
+                                     const ScalarB& B,
+                                     const ScalarTransform& T2) {
+      A += T1 * B * T2;
+    }
+  };
+
+  template <class MatrixA, typename FieldType, int n,
+            class TransformationMatrix>
+  struct TransformMatrixHelper<MatrixA, Dune::DiagonalMatrix<FieldType, n>,
+                               TransformationMatrix, false, false, false> {
+    static void addTransformedMatrix(
+        MatrixA& A, const TransformationMatrix& T1,
+        const Dune::DiagonalMatrix<FieldType, n>& B,
+        const TransformationMatrix& T2) {
+      for (size_t k = 0; k < n; ++k) {
+        typename TransformationMatrix::ConstColIterator Skj = T2[k].begin();
+        typename TransformationMatrix::ConstColIterator SkEnd = T2[k].end();
+        for (; Skj != SkEnd; ++Skj) {
+          typename TransformationMatrix::ConstColIterator Tki = T1[k].begin();
+          typename TransformationMatrix::ConstColIterator TkEnd = T1[k].end();
+          for (; Tki != TkEnd; Tki++)
+            if (A.exists(Tki.index(), Skj.index())) {
+              A[Tki.index()][Skj.index()] += (*Tki) * B.diagonal(k) * (*Skj);
+            }
+        }
+      }
+    }
+  };
+
+  template <class MatrixA, typename FieldType, int n,
+            class TransformationMatrix>
+  struct TransformMatrixHelper<MatrixA,
+                               Dune::ScaledIdentityMatrix<FieldType, n>,
+                               TransformationMatrix, false, false, false> {
+    static void addTransformedMatrix(
+        MatrixA& A, const TransformationMatrix& T1,
+        const Dune::ScaledIdentityMatrix<FieldType, n>& B,
+        const TransformationMatrix& T2) {
+      TransformMatrixHelper<MatrixA, FieldType, TransformationMatrix, false,
+                            true, false>::addTransformedMatrix(A, T1,
+                                                               B.scalar(), T2);
+    }
+  };
+
+  template <typename FieldType, int n, class TransformationMatrix>
+  struct TransformMatrixHelper<Dune::DiagonalMatrix<FieldType, n>,
+                               Dune::DiagonalMatrix<FieldType, n>,
+                               TransformationMatrix, false, false, false> {
+    static void addTransformedMatrix(
+        Dune::DiagonalMatrix<FieldType, n>& A, const TransformationMatrix& T1,
+        const Dune::DiagonalMatrix<FieldType, n>& B,
+        const TransformationMatrix& T2) {
+      for (int k = 0; k < n; k++) {
+        typename TransformationMatrix::ConstColIterator Tki = T1[k].begin();
+        typename TransformationMatrix::ConstColIterator TkEnd = T1[k].end();
+        for (; Tki != TkEnd; ++Tki)
+          A.diagonal(Tki.index()) +=
+              (*Tki) * B.diagonal(k) * T2[k][Tki.index()];
+      }
+    }
+  };
+
+  template <typename FieldType, int n, class TransformationMatrix>
+  struct TransformMatrixHelper<Dune::ScaledIdentityMatrix<FieldType, n>,
+                               Dune::ScaledIdentityMatrix<FieldType, n>,
+                               TransformationMatrix, false, false, false> {
+    static void addTransformedMatrix(
+        Dune::ScaledIdentityMatrix<FieldType, n>& A,
+        const TransformationMatrix& T1,
+        const Dune::ScaledIdentityMatrix<FieldType, n>& B,
+        const TransformationMatrix& T2) {
+      for (int k = 0; k < n; k++)
+        A.scalar() += T1[k][0] * B.scalar() * T2[k][0];
+    }
+  };
+
+  template <typename FieldType, int n>
+  struct TransformMatrixHelper<Dune::ScaledIdentityMatrix<FieldType, n>,
+                               Dune::ScaledIdentityMatrix<FieldType, n>,
+                               Dune::ScaledIdentityMatrix<FieldType, n>, false,
+                               false, false> {
+    static void addTransformedMatrix(
+        Dune::ScaledIdentityMatrix<FieldType, n>& A,
+        const Dune::ScaledIdentityMatrix<FieldType, n>& T1,
+        const Dune::ScaledIdentityMatrix<FieldType, n>& B,
+        const Dune::ScaledIdentityMatrix<FieldType, n>& T2) {
+      TransformMatrixHelper<FieldType, FieldType, FieldType, true, true,
+                            true>::addTransformedMatrix(A.scalar(), T1.scalar(),
+                                                        B.scalar(),
+                                                        T2.scalar());
+    }
+  };
+
+  template <class MatrixA, class MatrixB, class TransformationMatrix>
+  void addTransformedMatrix(MatrixA& A, const TransformationMatrix& T1,
+                            const MatrixB& B, const TransformationMatrix& T2) {
+    TransformMatrixHelper<
+        MatrixA, MatrixB, TransformationMatrix, ScalarTraits<MatrixA>::isScalar,
+        ScalarTraits<MatrixB>::isScalar,
+        ScalarTraits<TransformationMatrix>::isScalar>::addTransformedMatrix(A,
+                                                                            T1,
+                                                                            B,
+                                                                            T2);
+  }
+
+  template <class MatrixA, class MatrixB, class TransformationMatrix>
+  void transformMatrix(MatrixA& A, const TransformationMatrix& T1,
+                       const MatrixB& B, const TransformationMatrix& T2) {
+    A = 0;
+    TransformMatrixHelper<
+        MatrixA, MatrixB, TransformationMatrix, ScalarTraits<MatrixA>::isScalar,
+        ScalarTraits<MatrixB>::isScalar,
+        ScalarTraits<TransformationMatrix>::isScalar>::addTransformedMatrix(A,
+                                                                            T1,
+                                                                            B,
+                                                                            T2);
+  }
+
+  template <class MatrixBlockA, class MatrixB, class TransformationMatrix>
+  static void transformMatrix(Dune::BCRSMatrix<MatrixBlockA>& A,
+                              const TransformationMatrix& T1, const MatrixB& B,
+                              const TransformationMatrix& T2) {
+    transformMatrixPattern(A, T1, B, T2);
+    A = 0.0;
+    for (int k = 0; k < B.N(); ++k) {
+      typename MatrixB::row_type::ConstIterator BklIt = B[k].begin();
+      typename MatrixB::row_type::ConstIterator BklEnd = B[k].end();
+      for (; BklIt != BklEnd; ++BklIt) {
+        int l = BklIt.index();
+
+        typename TransformationMatrix::row_type::ConstIterator T1kiIt =
+            T1[k].begin();
+        typename TransformationMatrix::row_type::ConstIterator T1kiEnd =
+            T1[k].end();
+        for (; T1kiIt != T1kiEnd; ++T1kiIt) {
+          int i = T1kiIt.index();
+
+          typename TransformationMatrix::row_type::ConstIterator T2ljIt =
+              T2[l].begin();
+          typename TransformationMatrix::row_type::ConstIterator T2ljEnd =
+              T2[l].end();
+          for (; T2ljIt != T2ljEnd; ++T2ljIt) {
+            int j = T2ljIt.index();
+            MatrixBlockA Aij;
+            transformMatrix(Aij, *T1kiIt, *BklIt, *T2ljIt);
+            A[i][j] += Aij;
+          }
+        }
+      }
+    }
+  }
+
+  template <class MatrixBlockA, class MatrixB, class TransformationMatrix>
+  static void transformMatrixPattern(Dune::BCRSMatrix<MatrixBlockA>& A,
+                                     const TransformationMatrix& T1,
+                                     const MatrixB& B,
+                                     const TransformationMatrix& T2) {
+    Dune::MatrixIndexSet indices(T1.M(), T2.M());
+    for (int k = 0; k < B.N(); ++k) {
+      typename MatrixB::row_type::ConstIterator BklIt = B[k].begin();
+      typename MatrixB::row_type::ConstIterator BklEnd = B[k].end();
+      for (; BklIt != BklEnd; ++BklIt) {
+        int l = BklIt.index();
+
+        typename TransformationMatrix::row_type::ConstIterator T1kiIt =
+            T1[k].begin();
+        typename TransformationMatrix::row_type::ConstIterator T1kiEnd =
+            T1[k].end();
+        for (; T1kiIt != T1kiEnd; ++T1kiIt) {
+          int i = T1kiIt.index();
+
+          typename TransformationMatrix::row_type::ConstIterator T2ljIt =
+              T2[l].begin();
+          typename TransformationMatrix::row_type::ConstIterator T2ljEnd =
+              T2[l].end();
+          for (; T2ljIt != T2ljEnd; ++T2ljIt) {
+            int j = T2ljIt.index();
+            indices.add(i, j);
+          }
+        }
+      }
+    }
+    indices.exportIdx(A);
+  }
+}
+}
+
+#endif
-- 
GitLab