Skip to content
Snippets Groups Projects
fmatrix.hh 38.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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:
    
    Oliver Sander's avatar
    Oliver Sander committed
    #ifndef DUNE_FMATRIX_HH
    #define DUNE_FMATRIX_HH
    
    
    #include <cmath>
    #include <cstddef>
    
    Oliver Sander's avatar
    Oliver Sander committed
    #include <iostream>
    
    #include "exceptions.hh"
    #include "fvector.hh"
    #include "precision.hh"
    
    #include "static_assert.hh"
    
    Oliver Sander's avatar
    Oliver Sander committed
    
    namespace Dune {
    
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<class K, int ROWS, int COLS> class FieldMatrix;
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<class K, int ROWS, int COLS>
      struct FieldTraits< FieldMatrix<K,ROWS,COLS> >
    
      {
        typedef const typename FieldTraits<K>::field_type field_type;
        typedef const typename FieldTraits<K>::real_type real_type;
      };
    
    
    Oliver Sander's avatar
    Oliver Sander committed
      /**
    
    Martin Nolte's avatar
    Martin Nolte committed
          @addtogroup DenseMatVec
          @{
    
    Markus Blatt's avatar
    Markus Blatt committed
      /*! \file
    
         \brief  This file implements a matrix constructed from a given type
         representing a field and compile-time given number of rows and columns.
       */
    
    
    Christian Engwer's avatar
    Christian Engwer committed
      /**
         \brief you have to specialize this function for any type T that should be assignable to a FieldMatrix
       */
      template<class K, int ROWS, int COLS, typename T>
      void istl_assign_to_fmatrix(FieldMatrix<K,ROWS,COLS>& f, const T& t)
    
      {
        DUNE_THROW(NotImplemented, "You need to specialise this function for type T!");
      }
    
      namespace
      {
        template<bool b>
        struct Assigner
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          template<class K, int ROWS, int COLS, class T>
          static void assign(FieldMatrix<K,ROWS,COLS>& fm, const T& t)
    
          {
            istl_assign_to_fmatrix(fm, t);
          }
    
        };
    
    
        template<>
        struct Assigner<true>
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          template<class K, int ROWS, int COLS, class T>
          static void assign(FieldMatrix<K,ROWS,COLS>& fm, const T& t)
    
      /** @brief Error thrown if operations of a FieldMatrix fail. */
      class FMatrixError : public Exception {};
    
    
    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.
       */
    
    #ifdef DUNE_EXPRESSIONTEMPLATES
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<class K, int ROWS, int COLS>
      class FieldMatrix : ExprTmpl::Matrix< FieldMatrix<K,ROWS,COLS> >
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<class K, int ROWS, int COLS>
    
    Oliver Sander's avatar
    Oliver Sander committed
      class FieldMatrix
    
    Oliver Sander's avatar
    Oliver Sander committed
      {
      public:
        // standard constructor and everything is sufficient ...
    
        //===== type definitions and constants
    
        //! export the type representing the field
        typedef K field_type;
    
        //! export the type representing the components
        typedef K block_type;
    
    
        //! The type used for the index access and size operations.
        typedef std::size_t size_type;
    
    
    Oliver Sander's avatar
    Oliver Sander committed
        //! We are at the leaf of the block recursion
    
        enum {
          //! The number of block levels we contain. This is 1.
          blocklevel = 1
        };
    
    Oliver Sander's avatar
    Oliver Sander committed
    
        //! export size
    
    Christian Engwer's avatar
    Christian Engwer committed
          rows = ROWS,
    
    Christian Engwer's avatar
    Christian Engwer committed
          cols = COLS
    
    Christian Engwer's avatar
    Christian Engwer committed
        //! Each row is implemented by a field vector
        typedef FieldVector<K,cols> row_type;
    
    
    Oliver Sander's avatar
    Oliver Sander committed
        //===== constructors
        /** \brief Default constructor
         */
        FieldMatrix () {}
    
        /** \brief Constructor initializing the whole matrix with a scalar
         */
    
        explicit FieldMatrix (const K& k)
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++) p[i] = k;
    
        template<typename T>
        explicit FieldMatrix( const T& t)
        {
          Assigner<Conversion<T,K>::exists>::assign(*this, t);
        }
    
    
    Oliver Sander's avatar
    Oliver Sander committed
        //===== random access interface to rows of the matrix
    
        //! random access to the rows
    
        row_type& operator[] (size_type i)
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
          return p[i];
        }
    
        //! same for read only access
    
        const row_type& operator[] (size_type i) const
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
          return p[i];
        }
    
    
        //===== iterator interface to rows of the matrix
    
        //! Iterator class for sequential access
    
    Christian Engwer's avatar
    Christian Engwer committed
        typedef FieldIterator<FieldMatrix<K,rows,cols>,row_type> Iterator;
    
        //! typedef for stl compliant access
        typedef Iterator iterator;
        //! rename the iterators for easier access
        typedef Iterator RowIterator;
        //! rename the iterators for easier access
        typedef typename row_type::Iterator ColIterator;
    
    Oliver Sander's avatar
    Oliver Sander committed
    
        //! begin iterator
        Iterator begin ()
        {
    
          return Iterator(*this,0);
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! end iterator
        Iterator end ()
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          return Iterator(*this,rows);
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! begin iterator
        Iterator rbegin ()
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          return Iterator(*this,rows-1);
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! end iterator
        Iterator rend ()
        {
    
          return Iterator(*this,-1);
    
        //! Iterator class for sequential access
    
    Christian Engwer's avatar
    Christian Engwer committed
        typedef FieldIterator<const FieldMatrix<K,rows,cols>,const row_type> ConstIterator;
    
        //! typedef for stl compliant access
        typedef ConstIterator const_iterator;
    
    Oliver Sander's avatar
    Oliver Sander committed
        //! rename the iterators for easier access
    
        typedef ConstIterator ConstRowIterator;
        //! rename the iterators for easier access
        typedef typename row_type::ConstIterator ConstColIterator;
    
    Oliver Sander's avatar
    Oliver Sander committed
    
        //! begin iterator
        ConstIterator begin () const
        {
    
          return ConstIterator(*this,0);
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! end iterator
        ConstIterator end () const
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          return ConstIterator(*this,rows);
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! begin iterator
        ConstIterator rbegin () const
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          return ConstIterator(*this,rows-1);
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! end iterator
        ConstIterator rend () const
        {
    
          return ConstIterator(*this,-1);
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //===== assignment from scalar
        FieldMatrix& operator= (const K& k)
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
    
    Oliver Sander's avatar
    Oliver Sander committed
          return *this;
        }
    
    
        template<typename T>
        FieldMatrix& operator= ( const T& t)
        {
          Assigner<Conversion<T,K>::exists>::assign(*this, t);
          return *this;
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
        //===== vector space arithmetic
    
        //! vector space addition
        FieldMatrix& operator+= (const FieldMatrix& y)
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
    
    Oliver Sander's avatar
    Oliver Sander committed
          return *this;
        }
    
        //! vector space subtraction
        FieldMatrix& operator-= (const FieldMatrix& y)
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
    
    Oliver Sander's avatar
    Oliver Sander committed
          return *this;
        }
    
        //! vector space multiplication with scalar
        FieldMatrix& operator*= (const K& k)
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
    
    Oliver Sander's avatar
    Oliver Sander committed
          return *this;
        }
    
        //! vector space division by scalar
        FieldMatrix& operator/= (const K& k)
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
    
    Oliver Sander's avatar
    Oliver Sander committed
          return *this;
        }
    
    
        //! vector space axpy operation (*this += k y)
        FieldMatrix &axpy ( const K &k, const FieldMatrix &y )
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for( size_type i = 0; i < rows; ++i )
    
            p[ i ].axpy( k, y[ i ] );
          return *this;
        }
    
    
    Oliver Sander's avatar
    Oliver Sander committed
        //===== linear maps
    
    
        //! y = A x
        template<class X, class Y>
        void mv (const X& x, Y& y) const
        {
    #ifdef DUNE_FMatrix_WITH_CHECKING
    
          if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
    #endif
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; ++i)
    
    Christian Engwer's avatar
    Christian Engwer committed
            for (size_type j=0; j<cols; j++)
    
              y[i] += (*this)[i][j] * x[j];
    
        //! y = A^T x
        template< class X, class Y >
        void mtv ( const X &x, Y &y ) const
        {
    #ifdef DUNE_FMatrix_WITH_CHECKING
          assert( &x != &y );
          if( x.N() != N() )
            DUNE_THROW( FMatrixError, "Index out of range." );
          if( y.N() != M() )
            DUNE_THROW( FMatrixError, "Index out of range." );
    #endif
    
    Christian Engwer's avatar
    Christian Engwer committed
          for( size_type i = 0; i < cols; ++i )
    
    Christian Engwer's avatar
    Christian Engwer committed
            for( size_type j = 0; j < rows; ++j )
    
    Oliver Sander's avatar
    Oliver Sander committed
        //! y += A x
        template<class X, class Y>
        void umv (const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! y += A^T x
        template<class X, class Y>
        void umtv (const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
    
    Oliver Sander's avatar
    Oliver Sander committed
              y[j] += p[i][j]*x[i];
        }
    
        //! y += A^H x
        template<class X, class Y>
        void umhv (const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
              y[j] += conjugateComplex(p[i][j])*x[i];
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! y -= A x
        template<class X, class Y>
        void mmv (const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! y -= A^T x
        template<class X, class Y>
        void mmtv (const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
    
    Oliver Sander's avatar
    Oliver Sander committed
              y[j] -= p[i][j]*x[i];
        }
    
        //! y -= A^H x
        template<class X, class Y>
        void mmhv (const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
              y[j] -= conjugateComplex(p[i][j])*x[i];
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! y += alpha A x
        template<class X, class Y>
        void usmv (const K& alpha, const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! y += alpha A^T x
        template<class X, class Y>
        void usmtv (const K& alpha, const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
    
    Oliver Sander's avatar
    Oliver Sander committed
              y[j] += alpha*p[i][j]*x[i];
        }
    
        //! y += alpha A^H x
        template<class X, class Y>
        void usmhv (const K& alpha, const X& x, Y& y) const
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
          if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
            for (size_type j=0; j<cols; j++)
              y[j] += alpha*conjugateComplex(p[i][j])*x[i];
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //===== norms
    
        //! frobenius norm: sqrt(sum over squared values of entries)
    
        typename FieldTraits<K>::real_type frobenius_norm () const
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
          typename FieldTraits<K>::real_type sum=0;
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; ++i) sum += p[i].two_norm2();
    
    Oliver Sander's avatar
    Oliver Sander committed
          return sqrt(sum);
        }
    
        //! square of frobenius norm, need for block recursion
    
        typename FieldTraits<K>::real_type frobenius_norm2 () const
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
          typename FieldTraits<K>::real_type sum=0;
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; ++i) sum += p[i].two_norm2();
    
    Oliver Sander's avatar
    Oliver Sander committed
          return sum;
        }
    
        //! infinity norm (row sum norm, how to generalize for blocks?)
    
        typename FieldTraits<K>::real_type infinity_norm () const
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
          typename FieldTraits<K>::real_type max=0;
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; ++i) max = std::max(max,p[i].one_norm());
    
    Oliver Sander's avatar
    Oliver Sander committed
          return max;
        }
    
        //! simplified infinity norm (uses Manhattan norm for complex values)
    
        typename FieldTraits<K>::real_type infinity_norm_real () const
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
          typename FieldTraits<K>::real_type max=0;
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; ++i) max = std::max(max,p[i].one_norm_real());
    
    Oliver Sander's avatar
    Oliver Sander committed
          return max;
        }
    
        //===== solve
    
        /** \brief Solve system A x = b
         *
    
         * \exception FMatrixError if the matrix is singular
    
    Oliver Sander's avatar
    Oliver Sander committed
         */
    
    Christian Engwer's avatar
    Christian Engwer committed
        template <class V>
    
    Oliver Sander's avatar
    Oliver Sander committed
    
        /** \brief Compute inverse
         *
    
         * \exception FMatrixError if the matrix is singular
    
    Oliver Sander's avatar
    Oliver Sander committed
         */
    
    Oliver Sander's avatar
    Oliver Sander committed
    
        //! calculates the determinant of this matrix
        K determinant () const;
    
        //! Multiplies M from the left to this matrix
    
    Christian Engwer's avatar
    Christian Engwer committed
        FieldMatrix& leftmultiply (const FieldMatrix<K,rows,rows>& 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++) {
    
    Christian Engwer's avatar
    Christian Engwer committed
              for (size_type k=0; k<rows; k++)
    
    Oliver Sander's avatar
    Oliver Sander committed
          return *this;
        }
    
    
        //! Multiplies M from the left to this matrix, this matrix is not modified
        template<int l>
    
    Christian Engwer's avatar
    Christian Engwer committed
        FieldMatrix<K,l,cols> leftmultiplyany (const FieldMatrix<K,l,rows>& M)
    
    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++) {
    
    Christian Engwer's avatar
    Christian Engwer committed
              for (size_type k=0; k<rows; 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>
    
    Christian Engwer's avatar
    Christian Engwer committed
        FieldMatrix<K,rows,l> rightmultiplyany (const FieldMatrix<K,cols,l>& M)
    
    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;
        }
    
    
    Oliver Sander's avatar
    Oliver Sander committed
    
        //===== sizes
    
        //! number of blocks in row direction
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          return rows;
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //! number of blocks in column direction
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          return cols;
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
        //===== query
    
        //! return true when (i,j) is in pattern
    
        bool exists (size_type i, size_type j) const
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
    
    Oliver Sander's avatar
    Oliver Sander committed
          if (i<0 || i>=n) DUNE_THROW(FMatrixError,"row index out of range");
          if (j<0 || j>=m) DUNE_THROW(FMatrixError,"column index out of range");
    
    Oliver Sander's avatar
    Oliver Sander committed
    #endif
          return true;
        }
    
        //===== conversion operator
    
        /** \brief Sends the matrix to an output stream */
    
    Christian Engwer's avatar
    Christian Engwer committed
        friend std::ostream& operator<< (std::ostream& s, const FieldMatrix<K,rows,cols>& a)
    
    Oliver Sander's avatar
    Oliver Sander committed
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
    
            s << a.p[i] << std::endl;
    
    Oliver Sander's avatar
    Oliver Sander committed
          return s;
        }
    
      private:
    
        // the data, very simply a built in array with row-wise ordering
    
    Christian Engwer's avatar
    Christian Engwer committed
        row_type p[(rows > 0) ? rows : 1];
    
    Christian Engwer's avatar
    Christian Engwer committed
    #ifndef DOXYGEN
    
        struct ElimPivot
        {
    
    Christian Engwer's avatar
    Christian Engwer committed
          ElimPivot(size_type pivot[ROWS]);
    
    
          void swap(int i, int j);
    
          template<typename T>
          void operator()(const T&, int k, int i)
          {}
    
          size_type* pivot_;
        };
    
        template<typename V>
        struct Elim
        {
          Elim(V& rhs);
    
          void swap(int i, int j);
    
          void operator()(const typename V::field_type& factor, int k, int i);
    
          V* rhs_;
        };
    
    
        struct ElimDet
        {
          ElimDet(K& sign) : sign_(sign)
          { sign_ = 1; }
    
          void swap(int i, int j)
          { sign_ *= -1; }
    
          void operator()(const K&, int k, int i)
          {}
    
          K& sign_;
        };
    
    Christian Engwer's avatar
    Christian Engwer committed
    #endif // DOXYGEN
    
        template<class Func>
    
    Christian Engwer's avatar
    Christian Engwer committed
        void luDecomposition(FieldMatrix<K,ROWS,ROWS>& A, Func func) const;
    
    Christian Engwer's avatar
    Christian Engwer committed
    #ifndef DOXYGEN
      template<typename K, int ROWS, int COLS>
      FieldMatrix<K,ROWS,COLS>::ElimPivot::ElimPivot(size_type pivot[ROWS])
    
    Christian Engwer's avatar
    Christian Engwer committed
        for(int i=0; i < rows; ++i) pivot[i]=i;
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<typename K, int ROWS, int COLS>
      void FieldMatrix<K,ROWS,COLS>::ElimPivot::swap(int i, int j)
    
    Markus Blatt's avatar
     
    Markus Blatt committed
        pivot_[i]=j;
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<typename K, int ROWS, int COLS>
    
      template<typename V>
    
    Christian Engwer's avatar
    Christian Engwer committed
      FieldMatrix<K,ROWS,COLS>::Elim<V>::Elim(V& rhs)
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<typename K, int ROWS, int COLS>
    
      template<typename V>
    
    Christian Engwer's avatar
    Christian Engwer committed
      void FieldMatrix<K,ROWS,COLS>::Elim<V>::swap(int i, int j)
    
      {
        std::swap((*rhs_)[i], (*rhs_)[j]);
      }
    
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<typename K, int ROWS, int COLS>
    
      template<typename V>
    
    Christian Engwer's avatar
    Christian Engwer committed
      void FieldMatrix<K,ROWS,COLS>::
    
      Elim<V>::operator()(const typename V::field_type& factor, int k, int i)
      {
        (*rhs_)[k] -= factor*(*rhs_)[i];
      }
    
    Christian Engwer's avatar
    Christian Engwer committed
      template<typename K, int ROWS, int COLS>
    
      template<typename Func>
    
    Christian Engwer's avatar
    Christian Engwer committed
      inline void FieldMatrix<K,ROWS,COLS>::luDecomposition(FieldMatrix<K,ROWS,ROWS>& A, Func func) const
    
        typename FieldTraits<K>::real_type norm=A.infinity_norm_real(); // for relative thresholds
        typename FieldTraits<K>::real_type pivthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::pivoting_limit());
        typename FieldTraits<K>::real_type singthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::singular_limit());
    
    
        // LU decomposition of A in A
    
    Christian Engwer's avatar
    Christian Engwer committed
        for (int i=0; i<rows; i++)  // loop over all rows
    
          typename FieldTraits<K>::real_type pivmax=fvmeta_absreal(A[i][i]);
    
    
          // pivoting ?
          if (pivmax<pivthres)
          {
            // compute maximum of column
    
            int imax=i; typename FieldTraits<K>::real_type abs;
    
    Christian Engwer's avatar
    Christian Engwer committed
            for (int k=i+1; k<rows; k++)
    
              if ((abs=fvmeta_absreal(A[k][i]))>pivmax)
              {
                pivmax = abs; imax = k;
              }
            // swap rows
            if (imax!=i) {
    
    Christian Engwer's avatar
    Christian Engwer committed
              for (int j=0; j<rows; j++)
    
                std::swap(A[i][j],A[imax][j]);
    
    Martin Nolte's avatar
    Martin Nolte committed
              func.swap(i, imax); // swap the pivot or rhs
    
            }
          }
    
          // singular ?
          if (pivmax<singthres)
            DUNE_THROW(FMatrixError,"matrix is singular");
    
          // eliminate
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (int k=i+1; k<rows; k++)
    
          {
            K factor = A[k][i]/A[i][i];
            A[k][i] = factor;
    
    Christian Engwer's avatar
    Christian Engwer committed
            for (int j=i+1; j<rows; j++)
    
              A[k][j] -= factor*A[i][j];
            func(factor, k, i);
          }
        }
      }
    
    
    Christian Engwer's avatar
    Christian Engwer committed
      template <class K, int ROWS, int COLS>
    
    Christian Engwer's avatar
    Christian Engwer committed
      inline void FieldMatrix<K,ROWS,COLS>::solve(V& x, const V& b) const
    
      {
        // never mind those ifs, because they get optimized away
    
    Christian Engwer's avatar
    Christian Engwer committed
        if (rows!=cols)
          DUNE_THROW(FMatrixError, "Can't solve for a " << rows << "x" << cols << " matrix!");
    
        // no need to implement the case 1x1, because the whole matrix class is
        // specialized for this
    
    Christian Engwer's avatar
    Christian Engwer committed
        if (rows==2) {
    
    #ifdef DUNE_FMatrix_WITH_CHECKING
          K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0];
          if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit())
            DUNE_THROW(FMatrixError,"matrix is singular");
          detinv = 1/detinv;
    #else
          K detinv = 1.0/(p[0][0]*p[1][1]-p[0][1]*p[1][0]);
    #endif
    
          x[0] = detinv*(p[1][1]*b[0]-p[0][1]*b[1]);
          x[1] = detinv*(p[0][0]*b[1]-p[1][0]*b[0]);
    
    Christian Engwer's avatar
    Christian Engwer committed
        } else if (rows==3) {
    
    
          K d = determinant();
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (fvmeta_absreal(d)<FMatrixPrecision<>::absolute_limit())
            DUNE_THROW(FMatrixError,"matrix is singular");
    #endif
    
          x[0] = (b[0]*p[1][1]*p[2][2] - b[0]*p[2][1]*p[1][2]
                  - b[1] *p[0][1]*p[2][2] + b[1]*p[2][1]*p[0][2]
                  + b[2] *p[0][1]*p[1][2] - b[2]*p[1][1]*p[0][2]) / d;
    
          x[1] = (p[0][0]*b[1]*p[2][2] - p[0][0]*b[2]*p[1][2]
                  - p[1][0] *b[0]*p[2][2] + p[1][0]*b[2]*p[0][2]
                  + p[2][0] *b[0]*p[1][2] - p[2][0]*b[1]*p[0][2]) / d;
    
          x[2] = (p[0][0]*p[1][1]*b[2] - p[0][0]*p[2][1]*b[1]
                  - p[1][0] *p[0][1]*b[2] + p[1][0]*p[2][1]*b[0]
                  + p[2][0] *p[0][1]*b[1] - p[2][0]*p[1][1]*b[0]) / d;
    
    
    Martin Nolte's avatar
    Martin Nolte committed
          V& rhs = x; // use x to store rhs
          rhs = b; // copy data
    
          Elim<V> elim(rhs);
    
    Christian Engwer's avatar
    Christian Engwer committed
          FieldMatrix<K,rows,rows> A(*this);
    
          luDecomposition(A, elim);
    
    Christian Engwer's avatar
    Christian Engwer committed
          for(int i=rows-1; i>=0; i--) {
            for (int j=i+1; j<rows; j++)
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
    Christian Engwer's avatar
    Christian Engwer committed
      template <class K, int ROWS, int COLS>
      inline void FieldMatrix<K,ROWS,COLS>::invert()
    
      {
        // never mind those ifs, because they get optimized away
    
    Christian Engwer's avatar
    Christian Engwer committed
        if (rows!=cols)
          DUNE_THROW(FMatrixError, "Can't invert a " << rows << "x" << cols << " matrix!");
    
    
        // no need to implement the case 1x1, because the whole matrix class is
        // specialized for this
    
    
    Christian Engwer's avatar
    Christian Engwer committed
        if (rows==2) {
    
    
          K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0];
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit())
            DUNE_THROW(FMatrixError,"matrix is singular");
    #endif
          detinv = 1/detinv;
    
          K temp=p[0][0];
          p[0][0] =  p[1][1]*detinv;
          p[0][1] = -p[0][1]*detinv;
          p[1][0] = -p[1][0]*detinv;
          p[1][1] =  temp*detinv;
    
        } else {
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          FieldMatrix<K,rows,rows> A(*this);
          size_type pivot[rows];
    
          luDecomposition(A, ElimPivot(pivot));
    
    Christian Engwer's avatar
    Christian Engwer committed
          FieldMatrix<K,rows,cols>& L=A;
          FieldMatrix<K,rows,cols>& U=A;
    
    Christian Engwer's avatar
    Christian Engwer committed
          for(size_type i=0; i<rows; ++i)
    
    Markus Blatt's avatar
     
    Markus Blatt committed
            p[i][i]=1;
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=0; i<rows; i++)
    
    Christian Engwer's avatar
    Christian Engwer committed
              for (size_type k=0; k<rows; k++)
    
    Markus Blatt's avatar
     
    Markus Blatt committed
                p[i][k] -= L[i][j]*p[j][k];
    
    Christian Engwer's avatar
    Christian Engwer committed
          for (size_type i=rows; i>0;) {
    
    Markus Blatt's avatar
     
    Markus Blatt committed
            --i;
    
    Christian Engwer's avatar
    Christian Engwer committed
            for (size_type k=0; k<rows; k++) {
              for (size_type j=i+1; j<rows; j++)
    
    Markus Blatt's avatar
     
    Markus Blatt committed
                p[i][k] -= U[i][j]*p[j][k];
              p[i][k] /= U[i][i];
    
    Markus Blatt's avatar
     
    Markus Blatt committed
    
    
    Christian Engwer's avatar
    Christian Engwer committed
          for(size_type i=rows; i>0; ) {
    
    Markus Blatt's avatar
     
    Markus Blatt committed
            --i;
    
    Markus Blatt's avatar
     
    Markus Blatt committed
            if(i!=pivot[i])
    
    Christian Engwer's avatar
    Christian Engwer committed
              for(size_type j=0; j<rows; ++j)
    
    Markus Blatt's avatar
     
    Markus Blatt committed
                std::swap(p[j][pivot[i]], p[j][i]);
          }
    
    Oliver Sander's avatar
    Oliver Sander committed
        }
    
    Oliver Sander's avatar
    Oliver Sander committed
    
      // implementation of the determinant
    
    Christian Engwer's avatar
    Christian Engwer committed
      template <class K, int ROWS, int COLS>
      inline K FieldMatrix<K,ROWS,COLS>::determinant() const
    
    Oliver Sander's avatar
    Oliver Sander committed
      {
    
        // never mind those ifs, because they get optimized away
    
    Christian Engwer's avatar
    Christian Engwer committed
        if (rows!=cols)
          DUNE_THROW(FMatrixError, "There is no determinant for a " << rows << "x" << cols << " matrix!");
    
    
        // no need to implement the case 1x1, because the whole matrix class is
        // specialized for this
    
    
    Christian Engwer's avatar
    Christian Engwer committed
        if (rows==2)
    
    Christian Engwer's avatar
    Christian Engwer committed
        if (rows==3) {
    
          // code generated by maple
          K t4  = p[0][0] * p[1][1];
          K t6  = p[0][0] * p[1][2];
          K t8  = p[0][1] * p[1][0];
          K t10 = p[0][2] * p[1][0];
          K t12 = p[0][1] * p[2][0];
          K t14 = p[0][2] * p[2][0];
    
          return (t4*p[2][2]-t6*p[2][1]-t8*p[2][2]+
                  t10*p[2][1]+t12*p[1][2]-t14*p[1][1]);
    
        }
    
    
    Christian Engwer's avatar
    Christian Engwer committed
        FieldMatrix<K,rows,rows> A(*this);
    
        try
        {
          luDecomposition(A, ElimDet(det));
        }
        catch (FMatrixError&)
        {
          return 0;
        }
    
    Christian Engwer's avatar
    Christian Engwer committed
        for (int i = 0; i < rows; ++i)
    
          det *= A[i][i];
        return det;
    
      /** \brief Special type for 1x1 matrices
       */
      template<class K>
      class FieldMatrix<K,1,1>
      {
      public:
        // standard constructor and everything is sufficient ...
    
        //===== type definitions and constants
    
        //! export the type representing the field
        typedef K field_type;
    
        //! export the type representing the components
        typedef K block_type;
    
    
        //! The type used for index access and size operations
    
    Markus Blatt's avatar
    Markus Blatt committed
        typedef std::size_t 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
        };
    
        //! Each row is implemented by a field vector
        typedef FieldVector<K,1> row_type;
    
        //! export size
        enum {
          //! \brief The number of rows.
          //! This is always one for this type.
          rows = 1,
          n = 1,
          //! \brief The number of columns.
          //! This is always one for this type.
          cols = 1,
          m = 1
        };
    
    
        //===== constructors
        /** \brief Default constructor
         */
        FieldMatrix () {}
    
        /** \brief Constructor initializing the whole matrix with a scalar
         */
    
        FieldMatrix (const K& k)
    
        template<typename T>
        explicit FieldMatrix( const T& t)
        {
          Assigner<Conversion<T,K>::exists>::assign(*this, t);
        }
    
        //===== random access interface to rows of the matrix
    
        //! random access to the rows
    
        row_type& operator[] (size_type i)
    
        {
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
    #endif
          return a;
        }
    
        //! same for read only access
    
        const row_type& operator[] (size_type i) const
    
        {
    #ifdef DUNE_FMatrix_WITH_CHECKING
          if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
    #endif
          return a;
        }
    
        //===== iterator interface to rows of the matrix
        //! Iterator class for sequential access
    
    Christian Engwer's avatar
    Christian Engwer committed
        typedef FieldIterator<FieldMatrix<K,rows,cols>,row_type> Iterator;
    
        //! typedef for stl compliant access
        typedef Iterator iterator;
        //! rename the iterators for easier access
        typedef Iterator RowIterator;
        //! rename the iterators for easier access
        typedef typename row_type::Iterator ColIterator;
    
        //! begin iterator
        Iterator begin ()
        {
          return Iterator(*this,0);
        }
    
        //! end iterator
        Iterator end ()
        {
          return Iterator(*this,n);
        }
    
        //! begin iterator
        Iterator rbegin ()
        {
          return Iterator(*this,n-1);
        }
    
        //! end iterator
        Iterator rend ()