fmatrix.hh

Go to the documentation of this file.
00001 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
00002 // vi: set et ts=8 sw=2 sts=2:
00003 // $Id: fmatrix.hh 5942 2010-03-23 14:27:41Z christi $
00004 #ifndef DUNE_FMATRIX_HH
00005 #define DUNE_FMATRIX_HH
00006 
00007 #include <cmath>
00008 #include <cstddef>
00009 #include <iostream>
00010 
00011 #include <dune/common/misc.hh>
00012 #include <dune/common/exceptions.hh>
00013 #include <dune/common/fvector.hh>
00014 #include <dune/common/precision.hh>
00015 #include <dune/common/static_assert.hh>
00016 
00017 namespace Dune
00018 {
00019    
00020   template<class K, int ROWS, int COLS> class FieldMatrix;
00021 
00022   template<class K, int ROWS, int COLS>
00023   struct FieldTraits< FieldMatrix<K,ROWS,COLS> >
00024   {
00025     typedef const typename FieldTraits<K>::field_type field_type;
00026     typedef const typename FieldTraits<K>::real_type real_type;
00027   };
00028 
00043   template<class K, int ROWS, int COLS, typename T>
00044   void istl_assign_to_fmatrix(FieldMatrix<K,ROWS,COLS>& f, const T& t)
00045   {
00046     DUNE_THROW(NotImplemented, "You need to specialise this function for type T!");
00047   }
00048 
00049   namespace
00050   {
00051     template<bool b>
00052     struct Assigner
00053     {
00054       template<class K, int ROWS, int COLS, class T>
00055       static void assign(FieldMatrix<K,ROWS,COLS>& fm, const T& t)
00056       {
00057         istl_assign_to_fmatrix(fm, t);
00058       }
00059       
00060     };
00061     
00062 
00063     template<>
00064     struct Assigner<true>
00065     {
00066       template<class K, int ROWS, int COLS, class T>
00067       static void assign(FieldMatrix<K,ROWS,COLS>& fm, const T& t)
00068       {
00069         fm = static_cast<const K>(t);
00070       }
00071     };  
00072   }
00073   
00075   class FMatrixError : public Exception {};
00076 
00085 #ifdef DUNE_EXPRESSIONTEMPLATES
00086   template<class K, int ROWS, int COLS>
00087   class FieldMatrix : ExprTmpl::Matrix< FieldMatrix<K,ROWS,COLS> >
00088 #else
00089   template<class K, int ROWS, int COLS>
00090   class FieldMatrix
00091 #endif
00092   {
00093   public:
00094     // standard constructor and everything is sufficient ...
00095 
00096     //===== type definitions and constants
00097 
00099     typedef K field_type;
00100 
00102     typedef K block_type;
00103     
00105     typedef std::size_t size_type;
00106     
00108     enum {
00110       blocklevel = 1
00111     };
00112 
00114     enum {
00116       rows = ROWS, 
00118       cols = COLS
00119     };
00120 
00122     typedef FieldVector<K,cols> row_type; 
00123 
00124     //===== constructors
00127     FieldMatrix () {}
00128 
00131     explicit FieldMatrix (const K& k)
00132     {
00133       for (size_type i=0; i<rows; i++) p[i] = k;
00134     }
00135 
00136     template<typename T>
00137     explicit FieldMatrix( const T& t)
00138     {
00139       Assigner<Conversion<T,K>::exists>::assign(*this, t);
00140     }
00141     
00142     //===== random access interface to rows of the matrix
00143 
00145     row_type& operator[] (size_type i)
00146     {
00147 #ifdef DUNE_FMatrix_WITH_CHECKING
00148       if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
00149 #endif
00150       return p[i];
00151     }
00152 
00154     const row_type& operator[] (size_type i) const
00155     {
00156 #ifdef DUNE_FMatrix_WITH_CHECKING
00157       if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
00158 #endif
00159       return p[i];
00160     }
00161 
00162 
00163     //===== iterator interface to rows of the matrix
00165     typedef FieldIterator<FieldMatrix<K,rows,cols>,row_type> Iterator;
00167     typedef Iterator iterator;
00169     typedef Iterator RowIterator;
00171     typedef typename row_type::Iterator ColIterator;
00172 
00174     Iterator begin ()
00175     {
00176       return Iterator(*this,0);
00177     }
00178       
00180     Iterator end ()
00181     {
00182       return Iterator(*this,rows);
00183     }
00184 
00186     Iterator rbegin ()
00187     {
00188       return Iterator(*this,rows-1);
00189     }
00190       
00192     Iterator rend ()
00193     {
00194       return Iterator(*this,-1);
00195     }
00196 
00198     typedef FieldIterator<const FieldMatrix<K,rows,cols>,const row_type> ConstIterator;
00200     typedef ConstIterator const_iterator;
00202     typedef ConstIterator ConstRowIterator;
00204     typedef typename row_type::ConstIterator ConstColIterator;
00205 
00207     ConstIterator begin () const
00208     {
00209       return ConstIterator(*this,0);
00210     }
00211       
00213     ConstIterator end () const
00214     {
00215       return ConstIterator(*this,rows);
00216     }
00217 
00219     ConstIterator rbegin () const
00220     {
00221       return ConstIterator(*this,rows-1);
00222     }
00223       
00225     ConstIterator rend () const
00226     {
00227       return ConstIterator(*this,-1);
00228     }
00229 
00230     //===== assignment from scalar
00231     FieldMatrix& operator= (const K& k)
00232     {
00233       for (size_type i=0; i<rows; i++)
00234         p[i] = k;
00235       return *this;   
00236     }
00237 
00238     template<typename T>
00239     FieldMatrix& operator= ( const T& t)
00240     {
00241       Assigner<Conversion<T,K>::exists>::assign(*this, t);
00242       return *this;
00243     }
00244     //===== vector space arithmetic
00245 
00247     FieldMatrix& operator+= (const FieldMatrix& y)
00248     {
00249       for (size_type i=0; i<rows; i++)
00250         p[i] += y.p[i];
00251       return *this;
00252     }
00253 
00255     FieldMatrix& operator-= (const FieldMatrix& y)
00256     {
00257       for (size_type i=0; i<rows; i++)
00258         p[i] -= y.p[i];
00259       return *this;
00260     }
00261 
00263     FieldMatrix& operator*= (const K& k)
00264     {
00265       for (size_type i=0; i<rows; i++)
00266         p[i] *= k;
00267       return *this;
00268     }
00269 
00271     FieldMatrix& operator/= (const K& k)
00272     {
00273       for (size_type i=0; i<rows; i++)
00274         p[i] /= k;
00275       return *this;
00276     }
00277 
00279     FieldMatrix &axpy ( const K &k, const FieldMatrix &y )
00280     {
00281       for( size_type i = 0; i < rows; ++i )
00282         p[ i ].axpy( k, y[ i ] );
00283       return *this;
00284     }
00285 
00286     //===== linear maps
00287    
00289     template<class X, class Y>
00290     void mv (const X& x, Y& y) const
00291     {
00292 #ifdef DUNE_FMatrix_WITH_CHECKING
00293       assert(&x != &y);
00294       if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00295       if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00296 #endif
00297       for (size_type i=0; i<rows; ++i)
00298       {
00299         y[i] = 0;
00300         for (size_type j=0; j<cols; j++)
00301           y[i] += (*this)[i][j] * x[j];
00302       }
00303     }
00304 
00306     template< class X, class Y >
00307     void mtv ( const X &x, Y &y ) const
00308     {
00309 #ifdef DUNE_FMatrix_WITH_CHECKING
00310       assert( &x != &y );
00311       if( x.N() != N() )
00312         DUNE_THROW( FMatrixError, "Index out of range." );
00313       if( y.N() != M() )
00314         DUNE_THROW( FMatrixError, "Index out of range." );
00315 #endif
00316       for( size_type i = 0; i < cols; ++i )
00317       {
00318         y[ i ] = 0;
00319         for( size_type j = 0; j < rows; ++j )
00320           y[ i ] += (*this)[ j ][ i ] * x[ j ];
00321       }
00322     }
00323 
00325     template<class X, class Y>
00326     void umv (const X& x, Y& y) const
00327     {
00328 #ifdef DUNE_FMatrix_WITH_CHECKING
00329       if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00330       if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00331 #endif
00332       for (size_type i=0; i<rows; i++)
00333         for (size_type j=0; j<cols; j++)
00334           y[i] += (*this)[i][j] * x[j];
00335     }
00336 
00338     template<class X, class Y>
00339     void umtv (const X& x, Y& y) const
00340     {
00341 #ifdef DUNE_FMatrix_WITH_CHECKING
00342       if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00343       if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00344 #endif
00345       
00346       for (size_type i=0; i<rows; i++)
00347         for (size_type j=0; j<cols; j++)
00348           y[j] += p[i][j]*x[i];
00349     }
00350 
00352     template<class X, class Y>
00353     void umhv (const X& x, Y& y) const
00354     {
00355 #ifdef DUNE_FMatrix_WITH_CHECKING
00356       if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00357       if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00358 #endif
00359       
00360       for (size_type i=0; i<rows; i++)
00361         for (size_type j=0; j<cols; j++)
00362           y[j] += conjugateComplex(p[i][j])*x[i];
00363     }
00364 
00366     template<class X, class Y>
00367     void mmv (const X& x, Y& y) const
00368     {
00369 #ifdef DUNE_FMatrix_WITH_CHECKING
00370       if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00371       if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00372 #endif
00373       for (size_type i=0; i<rows; i++)
00374         for (size_type j=0; j<cols; j++)
00375           y[i] -= (*this)[i][j] * x[j];
00376     }
00377 
00379     template<class X, class Y>
00380     void mmtv (const X& x, Y& y) const
00381     {
00382 #ifdef DUNE_FMatrix_WITH_CHECKING
00383       if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00384       if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00385 #endif
00386       
00387       for (size_type i=0; i<rows; i++)
00388         for (size_type j=0; j<cols; j++)
00389           y[j] -= p[i][j]*x[i];
00390     }
00391 
00393     template<class X, class Y>
00394     void mmhv (const X& x, Y& y) const
00395     {
00396 #ifdef DUNE_FMatrix_WITH_CHECKING
00397       if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00398       if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00399 #endif
00400       
00401       for (size_type i=0; i<rows; i++)
00402         for (size_type j=0; j<cols; j++)
00403           y[j] -= conjugateComplex(p[i][j])*x[i];
00404     }
00405 
00407     template<class X, class Y>
00408     void usmv (const K& alpha, const X& x, Y& y) const
00409     {
00410 #ifdef DUNE_FMatrix_WITH_CHECKING
00411       if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00412       if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00413 #endif
00414       for (size_type i=0; i<rows; i++)
00415         for (size_type j=0; j<cols; j++)
00416           y[i] += alpha * (*this)[i][j] * x[j];
00417     }
00418 
00420     template<class X, class Y>
00421     void usmtv (const K& alpha, const X& x, Y& y) const
00422     {
00423 #ifdef DUNE_FMatrix_WITH_CHECKING
00424       if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00425       if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00426 #endif
00427       
00428       for (size_type i=0; i<rows; i++)
00429         for (size_type j=0; j<cols; j++)
00430           y[j] += alpha*p[i][j]*x[i];
00431     }
00432 
00434     template<class X, class Y>
00435     void usmhv (const K& alpha, const X& x, Y& y) const
00436     {
00437 #ifdef DUNE_FMatrix_WITH_CHECKING
00438       if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00439       if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00440 #endif
00441       
00442       for (size_type i=0; i<rows; i++)
00443         for (size_type j=0; j<cols; j++)
00444           y[j] += alpha*conjugateComplex(p[i][j])*x[i];
00445     }
00446 
00447     //===== norms
00448 
00450     typename FieldTraits<K>::real_type frobenius_norm () const
00451     {
00452       typename FieldTraits<K>::real_type sum=0;
00453       for (size_type i=0; i<rows; ++i) sum += p[i].two_norm2();
00454       return fvmeta::sqrt(sum);
00455     }
00456 
00458     typename FieldTraits<K>::real_type frobenius_norm2 () const
00459     {
00460       typename FieldTraits<K>::real_type sum=0;
00461       for (size_type i=0; i<rows; ++i) sum += p[i].two_norm2();
00462       return sum;
00463     }
00464 
00466     typename FieldTraits<K>::real_type infinity_norm () const
00467     {
00468       typename FieldTraits<K>::real_type max=0;
00469       for (size_type i=0; i<rows; ++i) max = std::max(max,p[i].one_norm());
00470       return max;
00471     }
00472 
00474     typename FieldTraits<K>::real_type infinity_norm_real () const
00475     {
00476       typename FieldTraits<K>::real_type max=0;
00477       for (size_type i=0; i<rows; ++i) max = std::max(max,p[i].one_norm_real());
00478       return max;
00479     }
00480 
00481     //===== solve
00482 
00487     template <class V>
00488     void solve (V& x, const V& b) const;
00489 
00494     void invert();
00495 
00497     K determinant () const;
00498 
00500     FieldMatrix& leftmultiply (const FieldMatrix<K,rows,rows>& M)
00501     {
00502       FieldMatrix<K,rows,cols> C(*this);
00503       
00504       for (size_type i=0; i<rows; i++)
00505         for (size_type j=0; j<cols; j++) {
00506           (*this)[i][j] = 0;
00507           for (size_type k=0; k<rows; k++)
00508             (*this)[i][j] += M[i][k]*C[k][j];
00509         }
00510       
00511       return *this;
00512     }
00513  
00515     template<int l>
00516     FieldMatrix<K,l,cols> leftmultiplyany (const FieldMatrix<K,l,rows>& M) const
00517     {
00518       FieldMatrix<K,l,cols> C;
00519       
00520       for (size_type i=0; i<l; i++) {
00521         for (size_type j=0; j<cols; j++) {
00522           C[i][j] = 0;
00523           for (size_type k=0; k<rows; k++)
00524             C[i][j] += M[i][k]*(*this)[k][j];
00525         }
00526       }
00527       return C;
00528     }
00529 
00531     FieldMatrix& rightmultiply (const FieldMatrix<K,cols,cols>& M)
00532     {
00533       FieldMatrix<K,rows,cols> C(*this);
00534       
00535       for (size_type i=0; i<rows; i++)
00536         for (size_type j=0; j<cols; j++) {
00537           (*this)[i][j] = 0;
00538           for (size_type k=0; k<cols; k++)
00539             (*this)[i][j] += C[i][k]*M[k][j];
00540         }
00541       return *this;
00542     }
00543 
00545     template<int l>
00546     FieldMatrix<K,rows,l> rightmultiplyany (const FieldMatrix<K,cols,l>& M) const
00547     {
00548       FieldMatrix<K,rows,l> C;
00549       
00550       for (size_type i=0; i<rows; i++) {
00551         for (size_type j=0; j<l; j++) {
00552           C[i][j] = 0;
00553           for (size_type k=0; k<cols; k++)
00554             C[i][j] += (*this)[i][k]*M[k][j];
00555         }
00556       }
00557       return C;
00558     }
00559 
00560 
00561     //===== sizes
00562 
00564     size_type N () const
00565     {
00566       return rows;
00567     }
00568 
00570     size_type M () const
00571     {
00572       return cols;
00573     }
00574 
00575     //===== query
00576     
00578     bool exists (size_type i, size_type j) const
00579     {
00580 #ifdef DUNE_FMatrix_WITH_CHECKING
00581       if (i<0 || i>=n) DUNE_THROW(FMatrixError,"row index out of range");
00582       if (j<0 || j>=m) DUNE_THROW(FMatrixError,"column index out of range");
00583 #endif
00584       return true;
00585     }
00586 
00587     //===== conversion operator
00588 
00590     friend std::ostream& operator<< (std::ostream& s, const FieldMatrix<K,rows,cols>& a)
00591     {
00592       for (size_type i=0; i<rows; i++)
00593         s << a.p[i] << std::endl;
00594       return s;
00595     }
00596 
00597   private:
00598     // the data, very simply a built in array with row-wise ordering
00599     row_type p[(rows > 0) ? rows : 1]; 
00600 
00601 #ifndef DOXYGEN
00602     struct ElimPivot
00603     {
00604       ElimPivot(size_type pivot[ROWS]);
00605       
00606       void swap(int i, int j);
00607       
00608       template<typename T>
00609       void operator()(const T&, int k, int i)
00610       {}
00611       
00612       size_type* pivot_;
00613     };
00614 
00615     template<typename V>
00616     struct Elim
00617     {
00618       Elim(V& rhs);
00619       
00620       void swap(int i, int j);
00621       
00622       void operator()(const typename V::field_type& factor, int k, int i);
00623 
00624       V* rhs_;
00625     };
00626 
00627     struct ElimDet
00628     {
00629       ElimDet(K& sign) : sign_(sign)
00630       { sign_ = 1; }
00631 
00632       void swap(int i, int j)
00633       { sign_ *= -1; }
00634 
00635       void operator()(const K&, int k, int i)
00636       {}
00637 
00638       K& sign_;
00639     };
00640 #endif // DOXYGEN
00641     
00642     template<class Func>
00643     void luDecomposition(FieldMatrix<K,ROWS,ROWS>& A, Func func) const;
00644   };
00645 
00646 #ifndef DOXYGEN
00647   template<typename K, int ROWS, int COLS>
00648   FieldMatrix<K,ROWS,COLS>::ElimPivot::ElimPivot(size_type pivot[ROWS])
00649     : pivot_(pivot)
00650   {
00651     for(int i=0; i < rows; ++i) pivot[i]=i;
00652   }
00653 
00654   template<typename K, int ROWS, int COLS>
00655   void FieldMatrix<K,ROWS,COLS>::ElimPivot::swap(int i, int j)
00656   {
00657     pivot_[i]=j;
00658   }
00659   
00660   template<typename K, int ROWS, int COLS>
00661   template<typename V>
00662   FieldMatrix<K,ROWS,COLS>::Elim<V>::Elim(V& rhs)
00663     : rhs_(&rhs)
00664   {}
00665   
00666    template<typename K, int ROWS, int COLS>
00667    template<typename V>
00668    void FieldMatrix<K,ROWS,COLS>::Elim<V>::swap(int i, int j)
00669    {
00670      std::swap((*rhs_)[i], (*rhs_)[j]);
00671    }
00672 
00673   template<typename K, int ROWS, int COLS>
00674   template<typename V>
00675   void FieldMatrix<K,ROWS,COLS>::
00676   Elim<V>::operator()(const typename V::field_type& factor, int k, int i)
00677   {
00678     (*rhs_)[k] -= factor*(*rhs_)[i];
00679   }
00680   template<typename K, int ROWS, int COLS>
00681   template<typename Func>
00682   inline void FieldMatrix<K,ROWS,COLS>::luDecomposition(FieldMatrix<K,ROWS,ROWS>& A, Func func) const
00683   {
00684     typename FieldTraits<K>::real_type norm=A.infinity_norm_real(); // for relative thresholds
00685     typename FieldTraits<K>::real_type pivthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::pivoting_limit());
00686     typename FieldTraits<K>::real_type singthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::singular_limit());
00687   
00688     // LU decomposition of A in A
00689     for (int i=0; i<rows; i++)  // loop over all rows
00690     {
00691       typename FieldTraits<K>::real_type pivmax=fvmeta::absreal(A[i][i]);
00692       
00693       // pivoting ?
00694       if (pivmax<pivthres)
00695       {
00696         // compute maximum of column
00697         int imax=i; typename FieldTraits<K>::real_type abs;
00698         for (int k=i+1; k<rows; k++)
00699           if ((abs=fvmeta::absreal(A[k][i]))>pivmax)
00700           {
00701             pivmax = abs; imax = k;
00702           }
00703         // swap rows
00704         if (imax!=i){
00705           for (int j=0; j<rows; j++)
00706             std::swap(A[i][j],A[imax][j]);
00707           func.swap(i, imax); // swap the pivot or rhs
00708         }
00709       }
00710     
00711       // singular ?
00712       if (pivmax<singthres)
00713         DUNE_THROW(FMatrixError,"matrix is singular");          
00714     
00715       // eliminate
00716       for (int k=i+1; k<rows; k++)
00717       {
00718         K factor = A[k][i]/A[i][i];
00719         A[k][i] = factor;
00720         for (int j=i+1; j<rows; j++)
00721           A[k][j] -= factor*A[i][j];
00722         func(factor, k, i);
00723       }
00724     }
00725   }
00726 
00727     template <class K, int ROWS, int COLS>
00728     template <class V>
00729     inline void FieldMatrix<K,ROWS,COLS>::solve(V& x, const V& b) const
00730     {
00731         // never mind those ifs, because they get optimized away
00732         if (rows!=cols)
00733             DUNE_THROW(FMatrixError, "Can't solve for a " << rows << "x" << cols << " matrix!");
00734 
00735         // no need to implement the case 1x1, because the whole matrix class is
00736         // specialized for this
00737         
00738         if (rows==2) {
00739             
00740 #ifdef DUNE_FMatrix_WITH_CHECKING
00741             K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0];
00742             if (fvmeta::absreal(detinv)<FMatrixPrecision<>::absolute_limit())
00743                 DUNE_THROW(FMatrixError,"matrix is singular");
00744             detinv = 1/detinv;
00745 #else
00746             K detinv = 1.0/(p[0][0]*p[1][1]-p[0][1]*p[1][0]);
00747 #endif
00748             
00749             x[0] = detinv*(p[1][1]*b[0]-p[0][1]*b[1]);
00750             x[1] = detinv*(p[0][0]*b[1]-p[1][0]*b[0]);
00751 
00752         } else if (rows==3) {
00753 
00754             K d = determinant();
00755 #ifdef DUNE_FMatrix_WITH_CHECKING
00756             if (fvmeta::absreal(d)<FMatrixPrecision<>::absolute_limit())
00757                 DUNE_THROW(FMatrixError,"matrix is singular");
00758 #endif
00759 
00760             x[0] = (b[0]*p[1][1]*p[2][2] - b[0]*p[2][1]*p[1][2]
00761                     - b[1] *p[0][1]*p[2][2] + b[1]*p[2][1]*p[0][2]
00762                     + b[2] *p[0][1]*p[1][2] - b[2]*p[1][1]*p[0][2]) / d;
00763 
00764             x[1] = (p[0][0]*b[1]*p[2][2] - p[0][0]*b[2]*p[1][2]
00765                     - p[1][0] *b[0]*p[2][2] + p[1][0]*b[2]*p[0][2]
00766                     + p[2][0] *b[0]*p[1][2] - p[2][0]*b[1]*p[0][2]) / d;
00767 
00768             x[2] = (p[0][0]*p[1][1]*b[2] - p[0][0]*p[2][1]*b[1]
00769                     - p[1][0] *p[0][1]*b[2] + p[1][0]*p[2][1]*b[0]
00770                     + p[2][0] *p[0][1]*b[1] - p[2][0]*p[1][1]*b[0]) / d;
00771 
00772         } else {
00773 
00774       V& rhs = x; // use x to store rhs
00775       rhs = b; // copy data
00776       Elim<V> elim(rhs);
00777       FieldMatrix<K,rows,rows> A(*this);
00778       
00779       luDecomposition(A, elim);
00780       
00781       // backsolve
00782       for(int i=rows-1; i>=0; i--){
00783         for (int j=i+1; j<rows; j++)
00784           rhs[i] -= A[i][j]*x[j];
00785         x[i] = rhs[i]/A[i][i];
00786       }
00787     }   
00788     }
00789 
00790     template <class K, int ROWS, int COLS>
00791     inline void FieldMatrix<K,ROWS,COLS>::invert()
00792     {
00793         // never mind those ifs, because they get optimized away
00794         if (rows!=cols)
00795             DUNE_THROW(FMatrixError, "Can't invert a " << rows << "x" << cols << " matrix!");
00796 
00797         // no need to implement the case 1x1, because the whole matrix class is
00798         // specialized for this
00799 
00800         if (rows==2) {
00801 
00802             K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0];
00803 #ifdef DUNE_FMatrix_WITH_CHECKING
00804             if (fvmeta::absreal(detinv)<FMatrixPrecision<>::absolute_limit())
00805                 DUNE_THROW(FMatrixError,"matrix is singular");        
00806 #endif
00807             detinv = 1/detinv;
00808 
00809             K temp=p[0][0];
00810             p[0][0] =  p[1][1]*detinv;
00811             p[0][1] = -p[0][1]*detinv;
00812             p[1][0] = -p[1][0]*detinv;
00813             p[1][1] =  temp*detinv;
00814 
00815         } else {
00816 
00817           FieldMatrix<K,rows,rows> A(*this);
00818           size_type pivot[rows];
00819           luDecomposition(A, ElimPivot(pivot));
00820           FieldMatrix<K,rows,cols>& L=A;
00821           FieldMatrix<K,rows,cols>& U=A;
00822           
00823           // initialize inverse
00824           *this=K();
00825         
00826           for(size_type i=0; i<rows; ++i)
00827             p[i][i]=1;
00828         
00829           // L Y = I; multiple right hand sides
00830           for (size_type i=0; i<rows; i++)
00831             for (size_type j=0; j<i; j++)
00832               for (size_type k=0; k<rows; k++)
00833                 p[i][k] -= L[i][j]*p[j][k];
00834   
00835           // U A^{-1} = Y
00836           for (size_type i=rows; i>0;){
00837             --i;
00838             for (size_type k=0; k<rows; k++){
00839               for (size_type j=i+1; j<rows; j++)
00840                 p[i][k] -= U[i][j]*p[j][k];
00841               p[i][k] /= U[i][i];
00842             }
00843           }
00844 
00845           for(size_type i=rows; i>0; ){
00846             --i;
00847             if(i!=pivot[i])
00848               for(size_type j=0; j<rows; ++j)
00849                 std::swap(p[j][pivot[i]], p[j][i]);
00850           }
00851         }
00852     }
00853 
00854     // implementation of the determinant 
00855     template <class K, int ROWS, int COLS>
00856     inline K FieldMatrix<K,ROWS,COLS>::determinant() const
00857     {
00858         // never mind those ifs, because they get optimized away
00859         if (rows!=cols)
00860             DUNE_THROW(FMatrixError, "There is no determinant for a " << rows << "x" << cols << " matrix!");
00861 
00862         // no need to implement the case 1x1, because the whole matrix class is
00863         // specialized for this
00864 
00865         if (rows==2)
00866             return p[0][0]*p[1][1] - p[0][1]*p[1][0]; 
00867 
00868         if (rows==3) {
00869              // code generated by maple 
00870             K t4  = p[0][0] * p[1][1];
00871             K t6  = p[0][0] * p[1][2];
00872             K t8  = p[0][1] * p[1][0];
00873             K t10 = p[0][2] * p[1][0];
00874             K t12 = p[0][1] * p[2][0];
00875             K t14 = p[0][2] * p[2][0];
00876         
00877             return (t4*p[2][2]-t6*p[2][1]-t8*p[2][2]+
00878                     t10*p[2][1]+t12*p[1][2]-t14*p[1][1]);
00879 
00880         }
00881 
00882         FieldMatrix<K,rows,rows> A(*this);
00883         K det;
00884         try
00885         {
00886           luDecomposition(A, ElimDet(det));
00887         }
00888         catch (FMatrixError&)
00889         {
00890           return 0;
00891         }
00892         for (int i = 0; i < rows; ++i)
00893           det *= A[i][i];
00894         return det;
00895     }
00896 
00899   template<class K>
00900   class FieldMatrix<K,1,1>
00901   {
00902   public:
00903     // standard constructor and everything is sufficient ...
00904 
00905     //===== type definitions and constants
00906 
00908     typedef K field_type;
00909 
00911     typedef K block_type;
00912 
00914     typedef std::size_t size_type;
00915     
00917     enum {
00920       blocklevel = 1
00921     };
00922 
00924     typedef FieldVector<K,1> row_type; 
00925 
00927     enum {
00930       rows = 1,
00931       n = 1,
00934       cols = 1,
00935       m = 1
00936     };
00937 
00938     //===== constructors
00941         FieldMatrix () {}
00942 
00945     FieldMatrix (const K& k)
00946     {
00947         a = k;
00948     }
00949     template<typename T>
00950     explicit FieldMatrix( const T& t)
00951     {
00952       Assigner<Conversion<T,K>::exists>::assign(*this, t);
00953     }
00954     //===== random access interface to rows of the matrix
00955 
00957     row_type& operator[] (size_type i)
00958     {
00959 #ifdef DUNE_FMatrix_WITH_CHECKING
00960       if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
00961 #endif
00962       return a;
00963     }
00964 
00966     const row_type& operator[] (size_type i) const
00967     {
00968 #ifdef DUNE_FMatrix_WITH_CHECKING
00969       if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
00970 #endif
00971       return a;
00972     }
00973 
00974     //===== iterator interface to rows of the matrix
00976     typedef FieldIterator<FieldMatrix<K,rows,cols>,row_type> Iterator;
00978     typedef Iterator iterator;
00980     typedef Iterator RowIterator;
00982     typedef typename row_type::Iterator ColIterator;
00983 
00985     Iterator begin ()
00986     {
00987       return Iterator(*this,0);
00988     }
00989       
00991     Iterator end ()
00992     {
00993       return Iterator(*this,n);
00994     }
00995 
00997     Iterator rbegin ()
00998     {
00999       return Iterator(*this,n-1);
01000     }
01001       
01003     Iterator rend ()
01004     {
01005       return Iterator(*this,-1);
01006     }
01007 
01009     typedef FieldIterator<const FieldMatrix<K,rows,cols>,const row_type> ConstIterator;
01011     typedef ConstIterator const_iterator;
01013     typedef ConstIterator ConstRowIterator;
01015     typedef typename row_type::ConstIterator ConstColIterator;
01016 
01018     ConstIterator begin () const
01019     {
01020       return ConstIterator(*this,0);
01021     }
01022       
01024     ConstIterator end () const
01025     {
01026       return ConstIterator(*this,n);
01027     }
01028 
01030     ConstIterator rbegin () const
01031     {
01032       return ConstIterator(*this,n-1);
01033     }
01034       
01036     ConstIterator rend () const
01037     {
01038       return ConstIterator(*this,-1);
01039     }
01040 
01041     //===== assignment from scalar
01042 
01043     FieldMatrix& operator= (const K& k)
01044     {
01045       a[0] = k;
01046       return *this;   
01047     }
01048 
01049     template<typename T>
01050     FieldMatrix& operator= ( const T& t)
01051     {
01052       Assigner<Conversion<T,K>::exists>::assign(*this, t);
01053       return *this;
01054     }
01055 
01056     //===== vector space arithmetic
01057 
01059     FieldMatrix& operator+= (const K& y)
01060     {
01061       a[0] += y;
01062       return *this;
01063     }
01064 
01066     FieldMatrix& operator-= (const K& y)
01067     {
01068       a[0] -= y;
01069       return *this;
01070     }
01071 
01073     FieldMatrix& operator*= (const K& k)
01074     {
01075       a[0] *= k;
01076       return *this;
01077     }
01078 
01080     FieldMatrix& operator/= (const K& k)
01081     {
01082       a[0] /= k;
01083       return *this;
01084     }
01085 
01087     FieldMatrix &axpy ( const K &k, const FieldMatrix &y )
01088     {
01089           a[ 0 ] += k * y.a[ 0 ];
01090       return *this;
01091     }
01092 
01093     //===== linear maps
01094    
01096     template<class X, class Y>
01097     void mv (const X& x, Y& y) const
01098     {
01099       y[0] = a[0] * x[0];
01100     }
01101 
01103     template<class X, class Y>
01104     void mtv ( const X &x, Y &y ) const
01105     {
01106       y[0] = a[ 0 ] * x[0];
01107     }
01108 
01110     template<class X, class Y>
01111     void umv (const X& x, Y& y) const
01112     {
01113       y[0] += a[0] * x[0];
01114     }
01115 
01117     template<class X, class Y>
01118     void umtv (const X& x, Y& y) const
01119     {
01120       y[0] += a[0] * x[0];
01121     }
01122 
01124     template<class X, class Y>
01125     void umhv (const X& x, Y& y) const
01126     {
01127       y[0] += conjugateComplex(a[0]) * x[0];
01128     }
01129 
01131     template<class X, class Y>
01132     void mmv (const X& x, Y& y) const
01133     {
01134       y[0] -= a[0] * x[0];
01135     }
01136 
01138     template<class X, class Y>
01139     void mmtv (const X& x, Y& y) const
01140     {
01141       y[0] -= a[0] * x[0];
01142     }
01143 
01145     template<class X, class Y>
01146     void mmhv (const X& x, Y& y) const
01147     {
01148       y[0] -= conjugateComplex(a[0]) * x[0];
01149     }
01150 
01152     template<class X, class Y>
01153     void usmv (const K& alpha, const X& x, Y& y) const
01154     {
01155       y[0] += alpha * a[0] * x[0];
01156     }
01157 
01159     template<class X, class Y>
01160     void usmtv (const K& alpha, const X& x, Y& y) const
01161     {
01162       y[0] += alpha * a[0] * x[0];
01163     }
01164 
01166     template<class X, class Y>
01167     void usmhv (const K& alpha, const X& x, Y& y) const
01168     {
01169       y[0] += alpha * conjugateComplex(a[0]) * x[0];
01170     }
01171 
01172     //===== norms
01173 
01175     typename FieldTraits<K>::real_type frobenius_norm () const
01176     {
01177       return fvmeta::sqrt(fvmeta::abs2(a[0]));
01178     }
01179 
01181     typename FieldTraits<K>::real_type frobenius_norm2 () const
01182     {
01183       return fvmeta::abs2(a[0]);
01184     }
01185 
01187     typename FieldTraits<K>::field_type infinity_norm () const
01188     {
01189       return std::abs(a[0]);
01190     }
01191 
01193     typename FieldTraits<K>::real_type infinity_norm_real () const
01194     {
01195       return fvmeta::absreal(a[0]);
01196     }
01197 
01198     //===== solve
01199 
01201     void solve (FieldVector<K,1>& x, const FieldVector<K,1>& b) const
01202     {
01203 #ifdef DUNE_FMatrix_WITH_CHECKING
01204     if (fvmeta::absreal(a[0][0])<FMatrixPrecision<>::absolute_limit())
01205       DUNE_THROW(FMatrixError,"matrix is singular");          
01206 #endif
01207       x.p = b.p/a[0];
01208     }
01209 
01211     void invert ()
01212     {
01213 #ifdef DUNE_FMatrix_WITH_CHECKING
01214             if (fvmeta::absreal(a[0][0])<FMatrixPrecision<>::absolute_limit())
01215                 DUNE_THROW(FMatrixError,"matrix is singular");        
01216 #endif
01217       a[0] = 1/a[0];
01218     }
01219 
01221     K determinant () const
01222     {
01223       return a[ 0 ];
01224     }
01225 
01227     FieldMatrix& leftmultiply (const FieldMatrix& M)
01228     {
01229       a[0] *= M.a[0];
01230       return *this;
01231     }
01232 
01234     template<int l>
01235     FieldMatrix<K,l,1> leftmultiplyany (const FieldMatrix<K,l,1>& M) const
01236     {
01237       FieldMatrix<K,l,1> C;
01238       for (size_type j=0; j<l; j++)
01239         C[j][0] = M[j][0]*a[0];
01240       return C;
01241     }
01242 
01244     FieldMatrix& rightmultiply (const FieldMatrix& M)
01245     {
01246       a[0] *= M.a[0];
01247       return *this;
01248     }
01249 
01251     template<int l>
01252     FieldMatrix<K,1,l> rightmultiplyany (const FieldMatrix<K,1,l>& M) const
01253     {
01254       FieldMatrix<K,1,l> C;
01255       
01256       for (size_type j=0; j<l; j++)
01257         C[0][j] = M[0][j]*a[0];
01258       return C;
01259     }
01260 
01261     //===== sizes
01262 
01264     size_type N () const
01265     {
01266       return 1;
01267     }
01268 
01270     size_type M () const
01271     {
01272       return 1;
01273     }
01274 
01276     size_type rowdim (size_type r) const
01277     {
01278       return 1;
01279     }
01280 
01282     size_type coldim (size_type c) const
01283     {
01284       return 1;
01285     }
01286 
01288     size_type rowdim () const
01289     {
01290       return 1;
01291     }
01292 
01294     size_type coldim () const
01295     {
01296       return 1;
01297     }
01298 
01299     //===== query
01300     
01302     bool exists (size_type i, size_type j) const 
01303     {
01304       return i==0 && j==0;
01305     }
01306 
01307     //===== conversion operator
01308 
01309     operator K () const {return a[0];}
01310 
01311     private:
01312     // the data, just a single row with a single scalar
01313     row_type a;
01314     
01315   };
01316 #endif // DOXYGEN
01317 
01318 namespace FMatrixHelp {
01319 
01321 template <typename K>
01322 static inline K invertMatrix (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
01323 {
01324   inverse[0][0] = 1.0/matrix[0][0];
01325   return matrix[0][0];
01326 }
01327 
01329 template <typename K>
01330 static inline K invertMatrix_retTransposed (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
01331 {
01332   return invertMatrix(matrix,inverse); 
01333 }
01334 
01335 
01337 template <typename K>
01338 static inline K invertMatrix (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
01339 {
01340   // code generated by maple 
01341   K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
01342   K det_1 = 1.0/det;
01343   inverse[0][0] =   matrix[1][1] * det_1;
01344   inverse[0][1] = - matrix[0][1] * det_1;
01345   inverse[1][0] = - matrix[1][0] * det_1;
01346   inverse[1][1] =   matrix[0][0] * det_1;
01347   return det;
01348 }
01349 
01352 template <typename K>
01353 static inline K invertMatrix_retTransposed (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
01354 {
01355   // code generated by maple 
01356   K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
01357   K det_1 = 1.0/det;
01358   inverse[0][0] =   matrix[1][1] * det_1;
01359   inverse[1][0] = - matrix[0][1] * det_1;
01360   inverse[0][1] = - matrix[1][0] * det_1;
01361   inverse[1][1] =   matrix[0][0] * det_1;
01362   return det;
01363 }
01364 
01366 template <typename K>
01367 static inline K invertMatrix (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
01368 {
01369   // code generated by maple 
01370   K t4  = matrix[0][0] * matrix[1][1];
01371   K t6  = matrix[0][0] * matrix[1][2];
01372   K t8  = matrix[0][1] * matrix[1][0];
01373   K t10 = matrix[0][2] * matrix[1][0];
01374   K t12 = matrix[0][1] * matrix[2][0];
01375   K t14 = matrix[0][2] * matrix[2][0];
01376 
01377   K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
01378            t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
01379   K t17 = 1.0/det;
01380 
01381   inverse[0][0] =  (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
01382   inverse[0][1] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
01383   inverse[0][2] =  (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
01384   inverse[1][0] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
01385   inverse[1][1] =  (matrix[0][0] * matrix[2][2] - t14) * t17;
01386   inverse[1][2] = -(t6-t10) * t17;
01387   inverse[2][0] =  (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
01388   inverse[2][1] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
01389   inverse[2][2] =  (t4-t8) * t17;
01390 
01391   return det;
01392 }
01393 
01395 template <typename K>
01396 static inline K invertMatrix_retTransposed (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
01397 {
01398   // code generated by maple 
01399   K t4  = matrix[0][0] * matrix[1][1];
01400   K t6  = matrix[0][0] * matrix[1][2];
01401   K t8  = matrix[0][1] * matrix[1][0];
01402   K t10 = matrix[0][2] * matrix[1][0];
01403   K t12 = matrix[0][1] * matrix[2][0];
01404   K t14 = matrix[0][2] * matrix[2][0];
01405 
01406   K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
01407            t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
01408   K t17 = 1.0/det;
01409 
01410   inverse[0][0] =  (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
01411   inverse[1][0] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
01412   inverse[2][0] =  (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
01413   inverse[0][1] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
01414   inverse[1][1] =  (matrix[0][0] * matrix[2][2] - t14) * t17;
01415   inverse[2][1] = -(t6-t10) * t17;
01416   inverse[0][2] =  (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
01417   inverse[1][2] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
01418   inverse[2][2] =  (t4-t8) * t17;
01419 
01420   return det;
01421 }
01422 
01424 template< class K, int m, int n, int p >
01425 static inline void multMatrix ( const FieldMatrix< K, m, n > &A,
01426                                 const FieldMatrix< K, n, p > &B,
01427                                 FieldMatrix< K, m, p > &ret )
01428 {
01429   typedef typename FieldMatrix< K, m, p > :: size_type size_type;
01430 
01431   for( size_type i = 0; i < m; ++i )
01432   {
01433     for( size_type j = 0; j < p; ++j )
01434     {
01435       ret[ i ][ j ] = K( 0 );
01436       for( size_type k = 0; k < n; ++k )
01437         ret[ i ][ j ] += A[ i ][ k ] * B[ k ][ j ];
01438     }
01439   }
01440 }
01441 
01443 template <typename K, int rows,int cols>
01444 static inline void multTransposedMatrix(const FieldMatrix<K,rows,cols> &matrix, FieldMatrix<K,cols,cols>& ret)
01445 {
01446   typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
01447   
01448   for(size_type i=0; i<cols; i++)
01449     for(size_type j=0; j<cols; j++)
01450     {
01451       ret[i][j]=0.0;
01452       for(size_type k=0; k<rows; k++)
01453         ret[i][j]+=matrix[k][i]*matrix[k][j];
01454     }
01455 }
01456 
01458 template <typename K, int rows,int cols>
01459 static inline void multAssign(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x, FieldVector<K,rows> & ret) 
01460 {
01461   typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
01462   
01463   for(size_type i=0; i<rows; ++i)
01464   {
01465     ret[i] = 0.0;
01466     for(size_type j=0; j<cols; ++j)
01467     {
01468       ret[i] += matrix[i][j]*x[j];
01469     }
01470   }
01471 }
01472 
01474 template <typename K, int rows, int cols>
01475 static inline void multAssignTransposed( const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x, FieldVector<K,cols> & ret) 
01476 {
01477   typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
01478   
01479   for(size_type i=0; i<cols; ++i)
01480   {
01481     ret[i] = 0.0;
01482     for(size_type j=0; j<rows; ++j)
01483       ret[i] += matrix[j][i]*x[j];
01484   }
01485 }
01486 
01488 template <typename K, int rows,int cols>
01489 static inline FieldVector<K,rows> mult(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x) 
01490 {
01491   FieldVector<K,rows> ret;
01492   multAssign(matrix,x,ret);
01493   return ret;
01494 }
01495 
01497 template <typename K, int rows, int cols>
01498 static inline FieldVector<K,cols> multTransposed(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x) 
01499 {
01500   FieldVector<K,cols> ret;
01501   multAssignTransposed( matrix, x, ret );
01502   return ret; 
01503 }
01504 
01505 } // end namespace FMatrixHelp 
01506 
01507 #ifdef DUNE_EXPRESSIONTEMPLATES
01508 template <class K, int N, int M>
01509 struct BlockType< FieldMatrix<K,N,M> >
01510 {
01511   typedef K type;
01512 };
01513 
01514 template <class K, int N, int M>
01515 struct FieldType< FieldMatrix<K,N,M> >
01516 {
01517   typedef K type;
01518 };
01519 #endif // DUNE_EXPRESSIONTEMPLATES
01520 
01523 } // end namespace
01524 
01525 #include "fmatrixev.hh"
01526 #endif
Generated on Mon Apr 26 10:45:21 2010 for dune-common by  doxygen 1.6.3