Skip to content
Snippets Groups Projects
fmatrix.hh 15 KiB
Newer Older
Oliver Sander's avatar
Oliver Sander committed
// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
// vi: set et ts=4 sw=2 sts=2:
#ifndef DUNE_FMATRIX_HH
#define DUNE_FMATRIX_HH

#include <cmath>
#include <cstddef>
Oliver Sander's avatar
Oliver Sander committed
#include <iostream>
Oliver Sander's avatar
Oliver Sander committed

#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>
#include <dune/common/densematrix.hh>
#include <dune/common/precision.hh>
#include <dune/common/std/constexpr.hh>
Oliver Sander's avatar
Oliver Sander committed

  /**
Martin Nolte's avatar
Martin Nolte committed
      @addtogroup DenseMatVec
      @{
Markus Blatt's avatar
Markus Blatt committed
  /*! \file

Oliver Sander's avatar
Oliver Sander committed
     \brief  Implements a matrix constructed from a given type
Markus Blatt's avatar
Markus Blatt committed
     representing a field and compile-time given number of rows and columns.
   */

  template< class K, int ROWS, int COLS > class FieldMatrix;
  template< class K, int ROWS, int COLS >
  struct DenseMatVecTraits< FieldMatrix<K,ROWS,COLS> >
    typedef FieldMatrix<K,ROWS,COLS> derived_type;

    // each row is implemented by a field vector
    typedef FieldVector<K,COLS> row_type;

    typedef row_type &row_reference;
    typedef const row_type &const_row_reference;

    typedef std::array<row_type,ROWS> container_type;
    typedef K value_type;
    typedef typename container_type::size_type size_type;
  };
  template< class K, int ROWS, int COLS >
  struct FieldTraits< FieldMatrix<K,ROWS,COLS> >
    typedef typename FieldTraits<K>::field_type field_type;
    typedef typename FieldTraits<K>::real_type real_type;
  };
Markus Blatt's avatar
Markus Blatt committed
  /**
      @brief A dense n x m matrix.

     Matrices represent linear maps from a vector space V to a vector space W.
Oliver Sander's avatar
Oliver Sander committed
       This class represents such a linear map by storing a two-dimensional
Oliver Sander's avatar
Oliver Sander committed
       %array of numbers of a given field type K. The number of rows and
Oliver Sander's avatar
Oliver Sander committed
       columns is given at compile time.
   */
Christian Engwer's avatar
Christian Engwer committed
  template<class K, int ROWS, int COLS>
  class FieldMatrix : public DenseMatrix< FieldMatrix<K,ROWS,COLS> >
Oliver Sander's avatar
Oliver Sander committed
  {
    std::array< FieldVector<K,COLS>, ROWS > _data;
    typedef DenseMatrix< FieldMatrix<K,ROWS,COLS> > Base;
Oliver Sander's avatar
Oliver Sander committed
  public:

    //! export size
Christian Engwer's avatar
Christian Engwer committed
      rows = ROWS,
Christian Engwer's avatar
Christian Engwer committed
      cols = COLS
Oliver Sander's avatar
Oliver Sander committed

    typedef typename Base::size_type size_type;
    typedef typename Base::row_type row_type;
    typedef typename Base::row_reference row_reference;
    typedef typename Base::const_row_reference const_row_reference;

Oliver Sander's avatar
Oliver Sander committed
    //===== constructors
    /** \brief Default constructor
     */
    FieldMatrix () {}

    /** \brief Constructor initializing the whole matrix with a scalar
     */
    template< class Other >
    FieldMatrix ( const Other &other )
Oliver Sander's avatar
Oliver Sander committed
    {
      DenseMatrixAssigner< FieldMatrix< K, ROWS, COLS >, Other >::apply( *this, other );
    /** \brief Constructor initializing the matrix from a list of lists of scalars
     */
    FieldMatrix (std::initializer_list<std::initializer_list<K> > const &ll)
    {
      assert(ll.size() == rows); // Actually, this is not needed any more!
      std::copy_n(ll.begin(), std::min(static_cast<std::size_t>(ROWS),
                                       ll.size()),
                 _data.begin());
    /** \brief Constructor initializing the matrix from a list of vector
     */
    FieldMatrix(std::initializer_list<Dune::FieldVector<K, cols> > const &l) {
      assert(l.size() == rows); // Actually, this is not needed any more!
      std::copy_n(l.begin(), std::min(static_cast<std::size_t>(ROWS),
                                      l.size()),
                 _data.begin());
    //===== assignment
    using Base::operator=;
    //! Multiplies M from the left to this matrix, this matrix is not modified
    template<int l>
    FieldMatrix<K,l,cols> leftmultiplyany (const FieldMatrix<K,l,rows>& M) const
Christian Engwer's avatar
Christian Engwer committed
      FieldMatrix<K,l,cols> C;

      for (size_type i=0; i<l; i++) {
Christian Engwer's avatar
Christian Engwer committed
        for (size_type j=0; j<cols; j++) {
Christian Engwer's avatar
Christian Engwer committed
          for (size_type k=0; k<rows; k++)
            C[i][j] += M[i][k]*(*this)[k][j];
        }
      }
      return C;
    }

Oliver Sander's avatar
Oliver Sander committed
    //! Multiplies M from the right to this matrix
Christian Engwer's avatar
Christian Engwer committed
    FieldMatrix& rightmultiply (const FieldMatrix<K,cols,cols>& M)
Oliver Sander's avatar
Oliver Sander committed
    {
Christian Engwer's avatar
Christian Engwer committed
      FieldMatrix<K,rows,cols> C(*this);
Christian Engwer's avatar
Christian Engwer committed
      for (size_type i=0; i<rows; i++)
        for (size_type j=0; j<cols; j++) {
          for (size_type k=0; k<cols; k++)
Oliver Sander's avatar
Oliver Sander committed
      return *this;
    }

    //! Multiplies M from the right to this matrix, this matrix is not modified
    template<int l>
    FieldMatrix<K,rows,l> rightmultiplyany (const FieldMatrix<K,cols,l>& M) const
Christian Engwer's avatar
Christian Engwer committed
      FieldMatrix<K,rows,l> C;
Christian Engwer's avatar
Christian Engwer committed
      for (size_type i=0; i<rows; i++) {
        for (size_type j=0; j<l; j++) {
          C[i][j] = 0;
Christian Engwer's avatar
Christian Engwer committed
          for (size_type k=0; k<cols; k++)
            C[i][j] += (*this)[i][k]*M[k][j];
        }
      }
      return C;
    }

    // make this thing a matrix
    DUNE_CONSTEXPR size_type mat_rows() const { return ROWS; }
    DUNE_CONSTEXPR size_type mat_cols() const { return COLS; }
      assert(i < ROWS);
      return _data[i];
Oliver Sander's avatar
Oliver Sander committed
    }

    const_row_reference mat_access ( size_type i ) const
    {
      assert(i < ROWS);
      return _data[i];
#ifndef DOXYGEN // hide specialization
  /** \brief Special type for 1x1 matrices
   */
  template<class K>
  class FieldMatrix<K,1,1> : public DenseMatrix< FieldMatrix<K,1,1> >
    FieldVector<K,1> _data;
    typedef DenseMatrix< FieldMatrix<K,1,1> > Base;
  public:
    // standard constructor and everything is sufficient ...

    //===== type definitions and constants

    //! The type used for index access and size operations
    typedef typename Base::size_type size_type;
    //! We are at the leaf of the block recursion
    enum {
      //! The number of block levels we contain.
      //! This is always one for this type.
      blocklevel = 1
    };

    typedef typename Base::row_type row_type;

    typedef typename Base::row_reference row_reference;
    typedef typename Base::const_row_reference const_row_reference;

    //! export size
    enum {
      //! \brief The number of rows.
      //! This is always one for this type.
      rows = 1,
      //! \brief The number of columns.
      //! This is always one for this type.
    //===== constructors
    /** \brief Default constructor
     */
    FieldMatrix () {}

    /** \brief Constructor initializing the whole matrix with a scalar
     */
    FieldMatrix (const K& k)
      _data[0] = k;

    template< class Other >
    FieldMatrix ( const Other &other )
      DenseMatrixAssigner< FieldMatrix< K, 1, 1 >, Other >::apply( *this, other );
    //! Multiplies M from the left to this matrix, this matrix is not modified
    template<int l>
    FieldMatrix<K,l,1> leftmultiplyany (const FieldMatrix<K,l,1>& M) const
    {
      FieldMatrix<K,l,1> C;
      for (size_type j=0; j<l; j++)
        C[j][0] = M[j][0]*(*this)[0][0];
    //! left multiplication
    FieldMatrix& rightmultiply (const FieldMatrix& M)
    {
      _data[0] *= M[0][0];
    //! Multiplies M from the right to this matrix, this matrix is not modified
    template<int l>
    FieldMatrix<K,1,l> rightmultiplyany (const FieldMatrix<K,1,l>& M) const
    {
      FieldMatrix<K,1,l> C;

      for (size_type j=0; j<l; j++)
        C[0][j] = M[0][j]*_data[0];
      return C;
    }
    // make this thing a matrix
    DUNE_CONSTEXPR size_type mat_rows() const { return 1; }
    DUNE_CONSTEXPR size_type mat_cols() const { return 1; }
      DUNE_UNUSED_PARAMETER(i);
      assert(i == 0);
      return _data;

    const_row_reference mat_access ( size_type i ) const
    {
      DUNE_UNUSED_PARAMETER(i);
      assert(i == 0);
      return _data;
    //! add scalar
    FieldMatrix& operator+= (const K& k)
    {
      _data[0] += k;
      return (*this);
    }

    //! subtract scalar
    FieldMatrix& operator-= (const K& k)
    {
      _data[0] -= k;
      return (*this);
    }

    //! multiplication with scalar
    FieldMatrix& operator*= (const K& k)
    {
      _data[0] *= k;
      return (*this);
    }

    //! division by scalar
    FieldMatrix& operator/= (const K& k)
    {
      _data[0] /= k;
      return (*this);
    }

    //===== conversion operator

    operator const K& () const { return _data[0]; }

  /** \brief Sends the matrix to an output stream */
  template<typename K>
  std::ostream& operator<< (std::ostream& s, const FieldMatrix<K,1,1>& a)
  {
    s << a[0][0];
    return s;
  }

Christian Engwer's avatar
Christian Engwer committed
#endif // DOXYGEN

  namespace FMatrixHelp {

    //! invert scalar without changing the original matrix
    template <typename K>
    static inline K invertMatrix (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
    {
Oliver Sander's avatar
Oliver Sander committed
      inverse[0][0] = 1.0/matrix[0][0];
      return matrix[0][0];
    //! invert scalar without changing the original matrix
    template <typename K>
    static inline K invertMatrix_retTransposed (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
    {
      return invertMatrix(matrix,inverse);
    }


    //! invert 2x2 Matrix without changing the original matrix
    template <typename K>
    static inline K invertMatrix (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
    {
      // code generated by maple
      K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
      K det_1 = 1.0/det;
      inverse[0][0] =   matrix[1][1] * det_1;
      inverse[0][1] = - matrix[0][1] * det_1;
      inverse[1][0] = - matrix[1][0] * det_1;
      inverse[1][1] =   matrix[0][0] * det_1;
      return det;
    }

    //! invert 2x2 Matrix without changing the original matrix
    //! return transposed matrix
    template <typename K>
    static inline K invertMatrix_retTransposed (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
    {
      // code generated by maple
      K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
      K det_1 = 1.0/det;
      inverse[0][0] =   matrix[1][1] * det_1;
      inverse[1][0] = - matrix[0][1] * det_1;
      inverse[0][1] = - matrix[1][0] * det_1;
      inverse[1][1] =   matrix[0][0] * det_1;
      return det;
    }

    //! invert 3x3 Matrix without changing the original matrix
    template <typename K>
    static inline K invertMatrix (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
    {
      // code generated by maple
      K t4  = matrix[0][0] * matrix[1][1];
      K t6  = matrix[0][0] * matrix[1][2];
      K t8  = matrix[0][1] * matrix[1][0];
      K t10 = matrix[0][2] * matrix[1][0];
      K t12 = matrix[0][1] * matrix[2][0];
      K t14 = matrix[0][2] * matrix[2][0];

      K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
               t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
      K t17 = 1.0/det;

      inverse[0][0] =  (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
      inverse[0][1] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
      inverse[0][2] =  (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
      inverse[1][0] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
      inverse[1][1] =  (matrix[0][0] * matrix[2][2] - t14) * t17;
      inverse[1][2] = -(t6-t10) * t17;
      inverse[2][0] =  (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
      inverse[2][1] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
      inverse[2][2] =  (t4-t8) * t17;

      return det;
    }

    //! invert 3x3 Matrix without changing the original matrix
    template <typename K>
    static inline K invertMatrix_retTransposed (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
    {
      // code generated by maple
      K t4  = matrix[0][0] * matrix[1][1];
      K t6  = matrix[0][0] * matrix[1][2];
      K t8  = matrix[0][1] * matrix[1][0];
      K t10 = matrix[0][2] * matrix[1][0];
      K t12 = matrix[0][1] * matrix[2][0];
      K t14 = matrix[0][2] * matrix[2][0];

      K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
               t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
      K t17 = 1.0/det;

      inverse[0][0] =  (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
      inverse[1][0] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
      inverse[2][0] =  (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
      inverse[0][1] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
      inverse[1][1] =  (matrix[0][0] * matrix[2][2] - t14) * t17;
      inverse[2][1] = -(t6-t10) * t17;
      inverse[0][2] =  (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
      inverse[1][2] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
      inverse[2][2] =  (t4-t8) * t17;

      return det;
    }

    //! calculates ret = A * B
    template< class K, int m, int n, int p >
    static inline void multMatrix ( const FieldMatrix< K, m, n > &A,
                                    const FieldMatrix< K, n, p > &B,
                                    FieldMatrix< K, m, p > &ret )
    {
      typedef typename FieldMatrix< K, m, p > :: size_type size_type;

      for( size_type i = 0; i < m; ++i )
      {
        for( size_type j = 0; j < p; ++j )
        {
          ret[ i ][ j ] = K( 0 );
          for( size_type k = 0; k < n; ++k )
            ret[ i ][ j ] += A[ i ][ k ] * B[ k ][ j ];
        }
      }
    }

    template <typename K, int rows, int cols>
    static inline void multTransposedMatrix(const FieldMatrix<K,rows,cols> &matrix, FieldMatrix<K,cols,cols>& ret)
    {
      typedef typename FieldMatrix<K,rows,cols>::size_type size_type;

      for(size_type i=0; i<cols; i++)
        for(size_type j=0; j<cols; j++)
Christian Engwer's avatar
Christian Engwer committed
        {
          ret[i][j]=0.0;
          for(size_type k=0; k<rows; k++)
Christian Engwer's avatar
Christian Engwer committed
            ret[i][j]+=matrix[k][i]*matrix[k][j];
        }
    using Dune::DenseMatrixHelp::multAssign;
    //! calculates ret = matrix^T * x
    template <typename K, int rows, int cols>
    static inline void multAssignTransposed( const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x, FieldVector<K,cols> & ret)
      typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
      for(size_type i=0; i<cols; ++i)
      {
        ret[i] = 0.0;
        for(size_type j=0; j<rows; ++j)
          ret[i] += matrix[j][i]*x[j];
      }
    }

    template <typename K, int rows, int cols>
    static inline FieldVector<K,rows> mult(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x)
      FieldVector<K,rows> ret;
    //! calculates ret = matrix^T * x
    template <typename K, int rows, int cols>
    static inline FieldVector<K,cols> multTransposed(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x)
      multAssignTransposed( matrix, x, ret );
Oliver Sander's avatar
Oliver Sander committed
  /** @} end documentation */

} // end namespace

#include "fmatrixev.hh"
Oliver Sander's avatar
Oliver Sander committed
#endif