fmatrix.hh

Go to the documentation of this file.
00001 // $Id: fmatrix.hh 5468 2009-03-05 07:33:54Z mnolte $
00002 #ifndef DUNE_FMATRIX_HH
00003 #define DUNE_FMATRIX_HH
00004 
00005 #include<cmath>
00006 #include<cstddef>
00007 #include<complex>
00008 #include<iostream>
00009 #include "exceptions.hh"
00010 #include "fvector.hh"
00011 #include "precision.hh"
00012 #include "static_assert.hh"
00013 
00014 namespace Dune {
00015    
00027   template<class K, int n, int m> class FieldMatrix;
00028 
00029   template<class K, int n, int m, typename T>
00030   void istl_assign_to_fmatrix(FieldMatrix<K,n,m>& f, const T& t)
00031   {
00032     DUNE_THROW(NotImplemented, "You need to specialise this function for type T!");
00033   }
00034 
00035   namespace
00036   {
00037     template<bool b>
00038     struct Assigner
00039     {
00040       template<class K, int n, int m, class T>
00041       static void assign(FieldMatrix<K,n,m>& fm, const T& t)
00042       {
00043         istl_assign_to_fmatrix(fm, t);
00044       }
00045       
00046     };
00047     
00048 
00049     template<>
00050     struct Assigner<true>
00051     {
00052       template<class K, int n, int m, class T>
00053       static void assign(FieldMatrix<K,n,m>& fm, const T& t)
00054       {
00055         fm = static_cast<const K>(t);
00056       }
00057     };  
00058   }
00059   
00061   class FMatrixError : public Exception {};
00062 
00063   // conjugate komplex does nothing for non-complex types
00064   template<class K>
00065   inline K fm_ck (const K& k)
00066   {
00067         return k;
00068   }
00069 
00070   // conjugate komplex
00071   template<class K>
00072   inline std::complex<K> fm_ck (const std::complex<K>& c)
00073   {
00074         return std::complex<K>(c.real(),-c.imag());
00075   }
00076 
00085 #ifdef DUNE_EXPRESSIONTEMPLATES
00086   template<class K, int n, int m>
00087   class FieldMatrix : ExprTmpl::Matrix< FieldMatrix<K,n,m> >
00088 #else
00089   template<class K, int n, int m>
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         typedef FieldVector<K,m> row_type; 
00115 
00117         enum {
00119           rows = n, 
00121           cols = m
00122         };
00123 
00124         //===== constructors
00127         FieldMatrix () {}
00128 
00131         FieldMatrix (const K& k)
00132         {
00133           for (size_type i=0; i<n; 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,n,m>,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,n);
00183         }
00184 
00186         Iterator rbegin ()
00187         {
00188           return Iterator(*this,n-1);
00189         }
00190           
00192         Iterator rend ()
00193         {
00194           return Iterator(*this,-1);
00195         }
00196 
00198     typedef FieldIterator<const FieldMatrix<K,n,m>,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,n);
00216         }
00217 
00219         ConstIterator rbegin () const
00220         {
00221           return ConstIterator(*this,n-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<n; 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<n; 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<n; 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<n; i++)
00266                 p[i] *= k;
00267           return *this;
00268         }
00269 
00271         FieldMatrix& operator/= (const K& k)
00272         {
00273             for (size_type i=0; i<n; 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 < n; ++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           if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00294           if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00295 #endif
00296     for (size_type i=0; i<n; ++i)
00297     {
00298       y[i] = 0;
00299       for (size_type j=0; j<m; j++)
00300         y[i] += (*this)[i][j] * x[j];
00301     }
00302         }
00303 
00305         template<class X, class Y>
00306         void umv (const X& x, Y& y) const
00307         {
00308 #ifdef DUNE_FMatrix_WITH_CHECKING
00309           if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00310           if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00311 #endif
00312           for (size_type i=0; i<n; i++)
00313               for (size_type j=0; j<m; j++)
00314                   y[i] += (*this)[i][j] * x[j];
00315         }
00316 
00318         template<class X, class Y>
00319         void umtv (const X& x, Y& y) const
00320         {
00321 #ifdef DUNE_FMatrix_WITH_CHECKING
00322           if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00323           if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00324 #endif
00325           
00326           for (size_type i=0; i<n; i++)
00327                   for (size_type j=0; j<m; j++)
00328                         y[j] += p[i][j]*x[i];
00329         }
00330 
00332         template<class X, class Y>
00333         void umhv (const X& x, Y& y) const
00334         {
00335 #ifdef DUNE_FMatrix_WITH_CHECKING
00336           if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00337           if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00338 #endif
00339           
00340           for (size_type i=0; i<n; i++)
00341                   for (size_type j=0; j<m; j++)
00342                         y[j] += fm_ck(p[i][j])*x[i];
00343         }
00344 
00346         template<class X, class Y>
00347         void mmv (const X& x, Y& y) const
00348         {
00349 #ifdef DUNE_FMatrix_WITH_CHECKING
00350           if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00351           if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00352 #endif
00353           for (size_type i=0; i<n; i++)
00354               for (size_type j=0; j<m; j++)
00355                   y[i] -= (*this)[i][j] * x[j];
00356         }
00357 
00359         template<class X, class Y>
00360         void mmtv (const X& x, Y& y) const
00361         {
00362 #ifdef DUNE_FMatrix_WITH_CHECKING
00363           if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00364           if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00365 #endif
00366           
00367           for (size_type i=0; i<n; i++)
00368                   for (size_type j=0; j<m; j++)
00369                         y[j] -= p[i][j]*x[i];
00370         }
00371 
00373         template<class X, class Y>
00374         void mmhv (const X& x, Y& y) const
00375         {
00376 #ifdef DUNE_FMatrix_WITH_CHECKING
00377           if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00378           if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00379 #endif
00380           
00381           for (size_type i=0; i<n; i++)
00382                   for (size_type j=0; j<m; j++)
00383                         y[j] -= fm_ck(p[i][j])*x[i];
00384         }
00385 
00387         template<class X, class Y>
00388         void usmv (const K& alpha, const X& x, Y& y) const
00389         {
00390 #ifdef DUNE_FMatrix_WITH_CHECKING
00391           if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00392           if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00393 #endif
00394           for (size_type i=0; i<n; i++)
00395               for (size_type j=0; j<m; j++)
00396                   y[i] += alpha * (*this)[i][j] * x[j];
00397         }
00398 
00400         template<class X, class Y>
00401         void usmtv (const K& alpha, const X& x, Y& y) const
00402         {
00403 #ifdef DUNE_FMatrix_WITH_CHECKING
00404           if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00405           if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00406 #endif
00407           
00408           for (size_type i=0; i<n; i++)
00409                   for (size_type j=0; j<m; j++)
00410                         y[j] += alpha*p[i][j]*x[i];
00411         }
00412 
00414         template<class X, class Y>
00415         void usmhv (const K& alpha, const X& x, Y& y) const
00416         {
00417 #ifdef DUNE_FMatrix_WITH_CHECKING
00418           if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
00419           if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
00420 #endif
00421           
00422           for (size_type i=0; i<n; i++)
00423                   for (size_type j=0; j<m; j++)
00424                         y[j] += alpha*fm_ck(p[i][j])*x[i];
00425         }
00426 
00427         //===== norms
00428 
00430     double frobenius_norm () const
00431         {
00432           double sum=0;
00433           for (size_type i=0; i<n; ++i) sum += p[i].two_norm2();
00434           return sqrt(sum);
00435         }
00436 
00438     double frobenius_norm2 () const
00439         {
00440           double sum=0;
00441           for (size_type i=0; i<n; ++i) sum += p[i].two_norm2();
00442           return sum;
00443         }
00444 
00446     double infinity_norm () const
00447         {
00448           double max=0;
00449           for (size_type i=0; i<n; ++i) max = std::max(max,p[i].one_norm());
00450           return max;
00451         }
00452 
00454         double infinity_norm_real () const
00455         {
00456           double max=0;
00457           for (size_type i=0; i<n; ++i) max = std::max(max,p[i].one_norm_real());
00458           return max;
00459         }
00460 
00461         //===== solve
00462 
00467         template<class V>
00468         void solve (V& x, const V& b) const;
00469 
00474       void invert();
00475 
00477       K determinant () const;
00478 
00480         FieldMatrix& leftmultiply (const FieldMatrix<K,n,n>& M)
00481         {
00482             FieldMatrix<K,n,m> C(*this);
00483             
00484             for (size_type i=0; i<n; i++)
00485                 for (size_type j=0; j<m; j++) {
00486                     (*this)[i][j] = 0;
00487                     for (size_type k=0; k<n; k++)
00488                         (*this)[i][j] += M[i][k]*C[k][j];
00489                 }
00490 
00491           return *this;
00492         }
00493 
00495         FieldMatrix& rightmultiply (const FieldMatrix<K,m,m>& M)
00496         {
00497             FieldMatrix<K,n,m> C(*this);
00498 
00499             for (size_type i=0; i<n; i++)
00500                 for (size_type j=0; j<m; j++) {
00501                     (*this)[i][j] = 0;
00502                     for (size_type k=0; k<m; k++)
00503                         (*this)[i][j] += C[i][k]*M[k][j];
00504                 }
00505             return *this;
00506         }
00507 
00508 
00509         //===== sizes
00510 
00512         size_type N () const
00513         {
00514           return n;
00515         }
00516 
00518         size_type M () const
00519         {
00520           return m;
00521         }
00522 
00523         //===== query
00524         
00526         bool exists (size_type i, size_type j) const
00527         {
00528 #ifdef DUNE_FMatrix_WITH_CHECKING
00529           if (i<0 || i>=n) DUNE_THROW(FMatrixError,"row index out of range");
00530           if (j<0 || j>=m) DUNE_THROW(FMatrixError,"column index out of range");
00531 #endif
00532           return true;
00533         }
00534 
00535         //===== conversion operator
00536 
00538       friend std::ostream& operator<< (std::ostream& s, const FieldMatrix<K,n,m>& a)
00539       {
00540           for (size_type i=0; i<n; i++)
00541               s << a.p[i] << std::endl;
00542           return s;
00543       }
00544 
00545   private:
00546         // the data, very simply a built in array with row-wise ordering
00547         row_type p[(n > 0) ? n : 1]; 
00548 
00549     struct ElimPivot
00550     {
00551       ElimPivot(size_type pivot[n]);
00552       
00553       void swap(int i, int j);
00554       
00555       template<typename T>
00556       void operator()(const T&, int k, int i)
00557       {}
00558       
00559       size_type* pivot_;
00560     };
00561 
00562     template<typename V>
00563     struct Elim
00564     {
00565       Elim(V& rhs);
00566       
00567       void swap(int i, int j);
00568       
00569       void operator()(const typename V::field_type& factor, int k, int i);
00570 
00571       V* rhs_;
00572     };
00573     
00574     template<class Func>
00575     void luDecomposition(FieldMatrix<K,n,n>& A, Func func) const;
00576   };
00577 
00578   template<typename K, int n, int m>
00579   FieldMatrix<K,n,m>::ElimPivot::ElimPivot(size_type pivot[n])
00580     : pivot_(pivot)
00581   {
00582     for(int i=0; i < n; ++i) pivot[i]=i;
00583   }
00584 
00585   template<typename K, int n, int m>
00586   void FieldMatrix<K,n,m>::ElimPivot::swap(int i, int j)
00587   {
00588     pivot_[i]=j;
00589   }
00590   
00591   template<typename K, int n, int m>
00592   template<typename V>
00593   FieldMatrix<K,n,m>::Elim<V>::Elim(V& rhs)
00594     : rhs_(&rhs)
00595   {}
00596   
00597    template<typename K, int n, int m>
00598    template<typename V>
00599    void FieldMatrix<K,n,m>::Elim<V>::swap(int i, int j)
00600    {
00601      std::swap((*rhs_)[i], (*rhs_)[j]);
00602    }
00603 
00604   template<typename K, int n, int m>
00605   template<typename V>
00606   void FieldMatrix<K,n,m>::
00607   Elim<V>::operator()(const typename V::field_type& factor, int k, int i)
00608   {
00609     (*rhs_)[k] -= factor*(*rhs_)[i];
00610   }
00611   template<typename K, int n, int m>
00612   template<typename Func>
00613   inline void FieldMatrix<K,n,m>::luDecomposition(FieldMatrix<K,n,n>& A, Func func) const
00614   {
00615     double norm=A.infinity_norm_real(); // for relative thresholds
00616     double pivthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::pivoting_limit());
00617     double singthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::singular_limit());
00618   
00619     // LU decomposition of A in A
00620     for (int i=0; i<n; i++)  // loop over all rows
00621       {
00622         double pivmax=fvmeta_absreal(A[i][i]);
00623       
00624         // pivoting ?
00625         if (pivmax<pivthres)
00626           {
00627             // compute maximum of column
00628             int imax=i; double abs;
00629             for (int k=i+1; k<n; k++)
00630               if ((abs=fvmeta_absreal(A[k][i]))>pivmax)
00631                 {
00632                   pivmax = abs; imax = k;
00633                 }
00634             // swap rows
00635             if (imax!=i){
00636               for (int j=0; j<n; j++)
00637                 std::swap(A[i][j],A[imax][j]);
00638               func.swap(i, imax); // swap the pivot or rhs
00639             }
00640           }
00641         
00642         // singular ?
00643         if (pivmax<singthres)
00644           DUNE_THROW(FMatrixError,"matrix is singular");                  
00645         
00646         // eliminate
00647         for (int k=i+1; k<n; k++)
00648           {
00649             K factor = A[k][i]/A[i][i];
00650             A[k][i] = factor;
00651             for (int j=i+1; j<n; j++)
00652               A[k][j] -= factor*A[i][j];
00653             func(factor, k, i);
00654           }
00655       }
00656   }
00657 
00658     template <class K, int n, int m>
00659     template <class V>
00660     inline void FieldMatrix<K,n,m>::solve(V& x, const V& b) const
00661     {
00662         // never mind those ifs, because they get optimized away
00663         if (n!=m)
00664             DUNE_THROW(FMatrixError, "Can't solve for a " << n << "x" << m << " matrix!");
00665 
00666         // no need to implement the case 1x1, because the whole matrix class is
00667         // specialized for this
00668         
00669         if (n==2) {
00670             
00671 #ifdef DUNE_FMatrix_WITH_CHECKING
00672             K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0];
00673             if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit())
00674                 DUNE_THROW(FMatrixError,"matrix is singular");
00675             detinv = 1/detinv;
00676 #else
00677             K detinv = 1.0/(p[0][0]*p[1][1]-p[0][1]*p[1][0]);
00678 #endif
00679             
00680             x[0] = detinv*(p[1][1]*b[0]-p[0][1]*b[1]);
00681             x[1] = detinv*(p[0][0]*b[1]-p[1][0]*b[0]);
00682 
00683         } else if (n==3) {
00684 
00685             K d = determinant();
00686 #ifdef DUNE_FMatrix_WITH_CHECKING
00687             if (fvmeta_absreal(d)<FMatrixPrecision<>::absolute_limit())
00688                 DUNE_THROW(FMatrixError,"matrix is singular");
00689 #endif
00690 
00691             x[0] = (b[0]*p[1][1]*p[2][2] - b[0]*p[2][1]*p[1][2]
00692                     - b[1] *p[0][1]*p[2][2] + b[1]*p[2][1]*p[0][2]
00693                     + b[2] *p[0][1]*p[1][2] - b[2]*p[1][1]*p[0][2]) / d;
00694 
00695             x[1] = (p[0][0]*b[1]*p[2][2] - p[0][0]*b[2]*p[1][2]
00696                     - p[1][0] *b[0]*p[2][2] + p[1][0]*b[2]*p[0][2]
00697                     + p[2][0] *b[0]*p[1][2] - p[2][0]*b[1]*p[0][2]) / d;
00698 
00699             x[2] = (p[0][0]*p[1][1]*b[2] - p[0][0]*p[2][1]*b[1]
00700                     - p[1][0] *p[0][1]*b[2] + p[1][0]*p[2][1]*b[0]
00701                     + p[2][0] *p[0][1]*b[1] - p[2][0]*p[1][1]*b[0]) / d;
00702 
00703         } else {
00704 
00705           V& rhs = x; // use x to store rhs
00706           rhs = b; // copy data
00707           Elim<V> elim(rhs);
00708           FieldMatrix<K,n,n> A(*this);
00709           
00710           luDecomposition(A, elim);
00711           
00712           // backsolve
00713           for(int i=n-1; i>=0; i--){
00714             for (int j=i+1; j<n; j++)
00715               rhs[i] -= A[i][j]*x[j];
00716             x[i] = rhs[i]/A[i][i];
00717           }
00718         }       
00719     }
00720 
00721     template <class K, int n, int m>
00722     inline void FieldMatrix<K,n,m>::invert()
00723     {
00724         // never mind those ifs, because they get optimized away
00725         if (n!=m)
00726             DUNE_THROW(FMatrixError, "Can't invert a " << n << "x" << m << " matrix!");
00727 
00728         // no need to implement the case 1x1, because the whole matrix class is
00729         // specialized for this
00730 
00731         if (n==2) {
00732 
00733             K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0];
00734 #ifdef DUNE_FMatrix_WITH_CHECKING
00735             if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit())
00736                 DUNE_THROW(FMatrixError,"matrix is singular");            
00737 #endif
00738             detinv = 1/detinv;
00739 
00740             K temp=p[0][0];
00741             p[0][0] =  p[1][1]*detinv;
00742             p[0][1] = -p[0][1]*detinv;
00743             p[1][0] = -p[1][0]*detinv;
00744             p[1][1] =  temp*detinv;
00745 
00746         } else {
00747 
00748             FieldMatrix<K,n,n> A(*this);
00749             size_type pivot[n];
00750             luDecomposition(A, ElimPivot(pivot));
00751             FieldMatrix<K,n,m>& L=A;
00752             FieldMatrix<K,n,m>& U=A;
00753             
00754             // initialize inverse
00755             *this=K();
00756             
00757             for(size_type i=0; i<n; ++i)
00758               p[i][i]=1;
00759             
00760             // L Y = I; multiple right hand sides
00761             for (size_type i=0; i<n; i++){
00762               for (size_type j=0; j<i; j++)
00763                 for (size_type k=0; k<n; k++)
00764                   p[i][k] -= L[i][j]*p[j][k];
00765             }
00766   
00767             // U A^{-1} = Y
00768             for (size_type i=n; i>0;){
00769               --i;
00770               for (size_type k=0; k<n; k++){
00771                 for (size_type j=i+1; j<n; j++)
00772                   p[i][k] -= U[i][j]*p[j][k];
00773                 p[i][k] /= U[i][i];
00774               }
00775             }
00776 
00777             for(size_type i=n; i>0; ){
00778               --i;
00779               if(i!=pivot[i])
00780                 for(size_type j=0; j<n; ++j)
00781                   std::swap(p[j][pivot[i]], p[j][i]);
00782             }
00783         }
00784     }
00785 
00786     // implementation of the determinant 
00787     template <class K, int n, int m>
00788     inline K FieldMatrix<K,n,m>::determinant() const
00789     {
00790         // never mind those ifs, because they get optimized away
00791         if (n!=m)
00792             DUNE_THROW(FMatrixError, "There is no determinant for a " << n << "x" << m << " matrix!");
00793 
00794         // no need to implement the case 1x1, because the whole matrix class is
00795         // specialized for this
00796 
00797         if (n==2)
00798             return p[0][0]*p[1][1] - p[0][1]*p[1][0]; 
00799 
00800         if (n==3) {
00801              // code generated by maple 
00802             K t4  = p[0][0] * p[1][1];
00803             K t6  = p[0][0] * p[1][2];
00804             K t8  = p[0][1] * p[1][0];
00805             K t10 = p[0][2] * p[1][0];
00806             K t12 = p[0][1] * p[2][0];
00807             K t14 = p[0][2] * p[2][0];
00808         
00809             return (t4*p[2][2]-t6*p[2][1]-t8*p[2][2]+
00810                     t10*p[2][1]+t12*p[1][2]-t14*p[1][1]);
00811 
00812         }
00813         
00814         DUNE_THROW(FMatrixError, "No implementation of determinantMatrix "
00815                    << "for FieldMatrix<" << n << "," << m << "> !");
00816 
00817     }
00818 
00819 
00822   template<class K>
00823   class FieldMatrix<K,1,1>
00824   {
00825   public:
00826         // standard constructor and everything is sufficient ...
00827 
00828         //===== type definitions and constants
00829 
00831         typedef K field_type;
00832 
00834         typedef K block_type;
00835 
00837     typedef std::size_t size_type;
00838     
00840         enum {
00843           blocklevel = 1
00844         };
00845 
00847         typedef FieldVector<K,1> row_type; 
00848 
00850         enum {
00853           rows = 1,
00854       n = 1,
00857           cols = 1,
00858       m = 1
00859         };
00860 
00861         //===== constructors
00864         FieldMatrix () {}
00865 
00868         FieldMatrix (const K& k)
00869         {
00870             a = k;
00871         }
00872     template<typename T>
00873     explicit FieldMatrix( const T& t)
00874     {
00875       Assigner<Conversion<T,K>::exists>::assign(*this, t);
00876     }
00877         //===== random access interface to rows of the matrix
00878 
00880         row_type& operator[] (size_type i)
00881         {
00882 #ifdef DUNE_FMatrix_WITH_CHECKING
00883           if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
00884 #endif
00885           return a;
00886         }
00887 
00889         const row_type& operator[] (size_type i) const
00890         {
00891 #ifdef DUNE_FMatrix_WITH_CHECKING
00892           if (i<0 || i>=n) DUNE_THROW(FMatrixError,"index out of range");
00893 #endif
00894           return a;
00895         }
00896 
00897         //===== iterator interface to rows of the matrix
00899     typedef FieldIterator<FieldMatrix<K,n,m>,row_type> Iterator;
00901     typedef Iterator iterator;
00903         typedef Iterator RowIterator;
00905         typedef typename row_type::Iterator ColIterator;
00906 
00908         Iterator begin ()
00909         {
00910           return Iterator(*this,0);
00911         }
00912           
00914         Iterator end ()
00915         {
00916           return Iterator(*this,n);
00917         }
00918 
00920         Iterator rbegin ()
00921         {
00922           return Iterator(*this,n-1);
00923         }
00924           
00926         Iterator rend ()
00927         {
00928           return Iterator(*this,-1);
00929         }
00930 
00932     typedef FieldIterator<const FieldMatrix<K,n,m>,const row_type> ConstIterator;
00934     typedef ConstIterator const_iterator;
00936         typedef ConstIterator ConstRowIterator;
00938         typedef typename row_type::ConstIterator ConstColIterator;
00939 
00941         ConstIterator begin () const
00942         {
00943           return ConstIterator(*this,0);
00944         }
00945           
00947         ConstIterator end () const
00948         {
00949           return ConstIterator(*this,n);
00950         }
00951 
00953         ConstIterator rbegin () const
00954         {
00955           return ConstIterator(*this,n-1);
00956         }
00957           
00959         ConstIterator rend () const
00960         {
00961           return ConstIterator(*this,-1);
00962         }
00963 
00964         //===== assignment from scalar
00965 
00966         FieldMatrix& operator= (const K& k)
00967         {
00968           a[0] = k;
00969           return *this;   
00970         }
00971 
00972     template<typename T>
00973     FieldMatrix& operator= ( const T& t)
00974     {
00975       Assigner<Conversion<T,K>::exists>::assign(*this, t);
00976       return *this;
00977     }
00978 
00979         //===== vector space arithmetic
00980 
00982         FieldMatrix& operator+= (const K& y)
00983         {
00984           a[0] += y;
00985           return *this;
00986         }
00987 
00989         FieldMatrix& operator-= (const K& y)
00990         {
00991           a[0] -= y;
00992           return *this;
00993         }
00994 
00996         FieldMatrix& operator*= (const K& k)
00997         {
00998           a[0] *= k;
00999           return *this;
01000         }
01001 
01003         FieldMatrix& operator/= (const K& k)
01004         {
01005           a[0] /= k;
01006           return *this;
01007         }
01008 
01010         FieldMatrix &axpy ( const K &k, const FieldMatrix &y )
01011         {
01012           a[ 0 ] += k * y.a[ 0 ];
01013           return *this;
01014         }
01015 
01016         //===== linear maps
01017    
01019         void mv (const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01020         {
01021           y.p = a[0] * x.p;
01022         }
01023 
01025         void umv (const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01026         {
01027           y.p += a[0] * x.p;
01028         }
01029 
01031         void umtv (const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01032         {
01033           y.p += a[0] * x.p;
01034         }
01035 
01037         void umhv (const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01038         {
01039           y.p += fm_ck(a[0]) * x.p;
01040         }
01041 
01043         void mmv (const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01044         {
01045           y.p -= a[0] * x.p;
01046         }
01047 
01049         void mmtv (const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01050         {
01051           y.p -= a[0] * x.p;
01052         }
01053 
01055         void mmhv (const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01056         {
01057           y.p -= fm_ck(a[0]) * x.p;
01058         }
01059 
01061         void usmv (const K& alpha, const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01062         {
01063           y.p += alpha * a[0] * x.p;
01064         }
01065 
01067         void usmtv (const K& alpha, const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01068         {
01069           y.p += alpha * a[0] * x.p;
01070         }
01071 
01073         void usmhv (const K& alpha, const FieldVector<K,1>& x, FieldVector<K,1>& y) const
01074         {
01075           y.p += alpha * fm_ck(a[0]) * x.p;
01076         }
01077 
01078         //===== norms
01079 
01081     double frobenius_norm () const
01082         {
01083           return sqrt(fvmeta_abs2(a[0]));
01084         }
01085 
01087     double frobenius_norm2 () const
01088         {
01089           return fvmeta_abs2(a[0]);
01090         }
01091 
01093     double infinity_norm () const
01094         {
01095             return std::abs(a[0]);
01096         }
01097 
01099         double infinity_norm_real () const
01100         {
01101           return fvmeta_abs_real(a[0]);
01102         }
01103 
01104         //===== solve
01105 
01107         void solve (FieldVector<K,1>& x, const FieldVector<K,1>& b) const
01108         {
01109 #ifdef DUNE_FMatrix_WITH_CHECKING
01110         if (fvmeta_absreal(a[0][0])<FMatrixPrecision<>::absolute_limit())
01111           DUNE_THROW(FMatrixError,"matrix is singular");                  
01112 #endif
01113           x.p = b.p/a[0];
01114         }
01115 
01117         void invert ()
01118         {
01119 #ifdef DUNE_FMatrix_WITH_CHECKING
01120             if (fvmeta_absreal(a[0][0])<FMatrixPrecision<>::absolute_limit())
01121                 DUNE_THROW(FMatrixError,"matrix is singular");            
01122 #endif
01123           a[0] = 1/a[0];
01124         }
01125 
01127     K determinant () const
01128     {
01129       return std::abs(a[0]);
01130     }
01131 
01133         FieldMatrix& leftmultiply (const FieldMatrix& M)
01134         {
01135           a[0] *= M.a[0];
01136           return *this;
01137         }
01138 
01140         FieldMatrix& rightmultiply (const FieldMatrix& M)
01141         {
01142           a[0] *= M.a[0];
01143           return *this;
01144         }
01145 
01146 
01147         //===== sizes
01148 
01150         size_type N () const
01151         {
01152           return 1;
01153         }
01154 
01156         size_type M () const
01157         {
01158           return 1;
01159         }
01160 
01162         size_type rowdim (size_type r) const
01163         {
01164           return 1;
01165         }
01166 
01168         size_type coldim (size_type c) const
01169         {
01170           return 1;
01171         }
01172 
01174         size_type rowdim () const
01175         {
01176           return 1;
01177         }
01178 
01180         size_type coldim () const
01181         {
01182           return 1;
01183         }
01184 
01185         //===== query
01186         
01188         bool exists (size_type i, size_type j) const 
01189         {
01190           return i==0 && j==0;
01191         }
01192 
01193         //===== conversion operator
01194 
01195         operator K () const {return a[0];}
01196 
01197         private:
01198         // the data, just a single row with a single scalar
01199     row_type a;
01200     
01201   };
01202 
01203 namespace FMatrixHelp {
01204 
01205 
01207 template <typename K>
01208 static inline K invertMatrix (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
01209 {
01210   inverse[0][0] = 1.0/matrix[0][0];
01211   return matrix[0][0];
01212 }
01213 
01215 template <typename K>
01216 static inline K invertMatrix_retTransposed (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
01217 {
01218   return invertMatrix(matrix,inverse); 
01219 }
01220 
01221 
01223 template <typename K>
01224 static inline K invertMatrix (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
01225 {
01226   // code generated by maple 
01227   K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
01228   K det_1 = 1.0/det;
01229   inverse[0][0] =   matrix[1][1] * det_1;
01230   inverse[0][1] = - matrix[0][1] * det_1;
01231   inverse[1][0] = - matrix[1][0] * det_1;
01232   inverse[1][1] =   matrix[0][0] * det_1;
01233   return det;
01234 }
01235 
01238 template <typename K>
01239 static inline K invertMatrix_retTransposed (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
01240 {
01241   // code generated by maple 
01242   K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
01243   K det_1 = 1.0/det;
01244   inverse[0][0] =   matrix[1][1] * det_1;
01245   inverse[1][0] = - matrix[0][1] * det_1;
01246   inverse[0][1] = - matrix[1][0] * det_1;
01247   inverse[1][1] =   matrix[0][0] * det_1;
01248   return det;
01249 }
01250 
01252 template <typename K>
01253 static inline K invertMatrix (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
01254 {
01255   // code generated by maple 
01256   K t4  = matrix[0][0] * matrix[1][1];
01257   K t6  = matrix[0][0] * matrix[1][2];
01258   K t8  = matrix[0][1] * matrix[1][0];
01259   K t10 = matrix[0][2] * matrix[1][0];
01260   K t12 = matrix[0][1] * matrix[2][0];
01261   K t14 = matrix[0][2] * matrix[2][0];
01262 
01263   K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
01264            t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
01265   K t17 = 1.0/det;
01266 
01267   inverse[0][0] =  (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
01268   inverse[0][1] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
01269   inverse[0][2] =  (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
01270   inverse[1][0] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
01271   inverse[1][1] =  (matrix[0][0] * matrix[2][2] - t14) * t17;
01272   inverse[1][2] = -(t6-t10) * t17;
01273   inverse[2][0] =  (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
01274   inverse[2][1] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
01275   inverse[2][2] =  (t4-t8) * t17;
01276 
01277   return det;
01278 }
01279 
01281 template <typename K>
01282 static inline K invertMatrix_retTransposed (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
01283 {
01284   // code generated by maple 
01285   K t4  = matrix[0][0] * matrix[1][1];
01286   K t6  = matrix[0][0] * matrix[1][2];
01287   K t8  = matrix[0][1] * matrix[1][0];
01288   K t10 = matrix[0][2] * matrix[1][0];
01289   K t12 = matrix[0][1] * matrix[2][0];
01290   K t14 = matrix[0][2] * matrix[2][0];
01291 
01292   K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
01293            t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
01294   K t17 = 1.0/det;
01295 
01296   inverse[0][0] =  (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
01297   inverse[1][0] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
01298   inverse[2][0] =  (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
01299   inverse[0][1] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
01300   inverse[1][1] =  (matrix[0][0] * matrix[2][2] - t14) * t17;
01301   inverse[2][1] = -(t6-t10) * t17;
01302   inverse[0][2] =  (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
01303   inverse[1][2] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
01304   inverse[2][2] =  (t4-t8) * t17;
01305 
01306   return det;
01307 }
01308 
01310 template< class K, int m, int n, int p >
01311 static inline void multMatrix ( const FieldMatrix< K, m, n > &A,
01312                                 const FieldMatrix< K, n, p > &B,
01313                                 FieldMatrix< K, m, p > &ret )
01314 {
01315   typedef typename FieldMatrix< K, m, p > :: size_type size_type;
01316 
01317   for( size_type i = 0; i < m; ++i )
01318   {
01319     for( size_type j = 0; j < p; ++j )
01320     {
01321       ret[ i ][ j ] = K( 0 );
01322       for( size_type k = 0; k < n; ++k )
01323         ret[ i ][ j ] += A[ i ][ k ] * B[ k ][ j ];
01324     }
01325   }
01326 }
01327 
01329 template <typename K, int rows,int cols>
01330 static inline void multTransposedMatrix(const FieldMatrix<K,rows,cols> &matrix, FieldMatrix<K,cols,cols>& ret)
01331 {
01332   typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
01333   
01334   for(size_type i=0; i<cols; i++)
01335     for(size_type j=0; j<cols; j++)
01336       { ret[i][j]=0.0;
01337         for(size_type k=0; k<rows; k++)
01338           ret[i][j]+=matrix[k][i]*matrix[k][j];
01339       }
01340 }
01341 
01343 template <typename K, int rows,int cols>
01344 static inline void multAssign(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x, FieldVector<K,rows> & ret) 
01345 {
01346   typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
01347   
01348   for(size_type i=0; i<rows; ++i)
01349   {
01350     ret[i] = 0.0;
01351     for(size_type j=0; j<cols; ++j)
01352     {
01353       ret[i] += matrix[i][j]*x[j];
01354     }
01355   }
01356 }
01357 
01359 template <typename K, int rows, int cols>
01360 static inline void multAssignTransposed( const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x, FieldVector<K,cols> & ret) 
01361 {
01362   typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
01363   
01364   for(size_type i=0; i<cols; ++i)
01365   {
01366     ret[i] = 0.0;
01367     for(size_type j=0; j<rows; ++j)
01368       ret[i] += matrix[j][i]*x[j];
01369   }
01370 }
01371 
01373 template <typename K, int rows,int cols>
01374 static inline FieldVector<K,rows> mult(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x) 
01375 {
01376   FieldVector<K,rows> ret;
01377   multAssign(matrix,x,ret);
01378   return ret;
01379 }
01380 
01382 template <typename K, int rows, int cols>
01383 static inline FieldVector<K,cols> multTransposed(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x) 
01384 {
01385   FieldVector<K,cols> ret;
01386   multAssignTransposed( matrix, x, ret );
01387   return ret; 
01388 }
01389 
01390 } // end namespace FMatrixHelp 
01391 
01392 #ifdef DUNE_EXPRESSIONTEMPLATES
01393 template <class K, int N, int M>
01394 struct BlockType< FieldMatrix<K,N,M> >
01395 {
01396   typedef K type;
01397 };
01398 
01399 template <class K, int N, int M>
01400 struct FieldType< FieldMatrix<K,N,M> >
01401 {
01402   typedef K type;
01403 };
01404 #endif // DUNE_EXPRESSIONTEMPLATES
01405 
01408 } // end namespace
01409 
01410 #endif

Generated on Tue Jul 28 22:27:49 2009 for dune-common by  doxygen 1.5.6