00001
00002
00003
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
00095
00096
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
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
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
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
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
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
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
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
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
00562
00564 size_type N () const
00565 {
00566 return rows;
00567 }
00568
00570 size_type M () const
00571 {
00572 return cols;
00573 }
00574
00575
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
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
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();
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
00689 for (int i=0; i<rows; i++)
00690 {
00691 typename FieldTraits<K>::real_type pivmax=fvmeta::absreal(A[i][i]);
00692
00693
00694 if (pivmax<pivthres)
00695 {
00696
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
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);
00708 }
00709 }
00710
00711
00712 if (pivmax<singthres)
00713 DUNE_THROW(FMatrixError,"matrix is singular");
00714
00715
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
00732 if (rows!=cols)
00733 DUNE_THROW(FMatrixError, "Can't solve for a " << rows << "x" << cols << " matrix!");
00734
00735
00736
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;
00775 rhs = b;
00776 Elim<V> elim(rhs);
00777 FieldMatrix<K,rows,rows> A(*this);
00778
00779 luDecomposition(A, elim);
00780
00781
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
00794 if (rows!=cols)
00795 DUNE_THROW(FMatrixError, "Can't invert a " << rows << "x" << cols << " matrix!");
00796
00797
00798
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
00824 *this=K();
00825
00826 for(size_type i=0; i<rows; ++i)
00827 p[i][i]=1;
00828
00829
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
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
00855 template <class K, int ROWS, int COLS>
00856 inline K FieldMatrix<K,ROWS,COLS>::determinant() const
00857 {
00858
00859 if (rows!=cols)
00860 DUNE_THROW(FMatrixError, "There is no determinant for a " << rows << "x" << cols << " matrix!");
00861
00862
00863
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
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
00904
00905
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
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
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
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
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
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
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
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
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
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
01300
01302 bool exists (size_type i, size_type j) const
01303 {
01304 return i==0 && j==0;
01305 }
01306
01307
01308
01309 operator K () const {return a[0];}
01310
01311 private:
01312
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
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
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
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
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 }
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 }
01524
01525 #include "fmatrixev.hh"
01526 #endif