dune-common  2.2.0
densematrix.hh
Go to the documentation of this file.
1 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi: set et ts=8 sw=2 sts=2:
3 // $Id: fmatrix.hh 6128 2010-09-08 13:50:00Z christi $
4 #ifndef DUNE_DENSEMATRIX_HH
5 #define DUNE_DENSEMATRIX_HH
6 
7 #include <cmath>
8 #include <cstddef>
9 #include <iostream>
10 #include <vector>
11 
12 #include <dune/common/misc.hh>
14 #include <dune/common/fvector.hh>
15 #include <dune/common/precision.hh>
17 #include <dune/common/classname.hh>
18 
19 
20 namespace Dune
21 {
22 
23  template<typename M> class DenseMatrix;
24 
25  template<typename M>
26  struct FieldTraits< DenseMatrix<M> >
27  {
30  };
31 
32  /*
33  work around a problem of FieldMatrix/FieldVector,
34  there is no unique way to obtain the size of a class
35  */
36  template<class K, int N, int M> class FieldMatrix;
37  template<class K, int N> class FieldVector;
38  namespace {
39  template<class V>
40  struct VectorSize
41  {
42  static typename V::size_type size(const V & v) { return v.size(); }
43  };
44 
45  template<class K, int N>
46  struct VectorSize< const FieldVector<K,N> >
47  {
48  typedef FieldVector<K,N> V;
49  static typename V::size_type size(const V & v) { return N; }
50  };
51  }
52 
68  template<typename M, typename T>
70  {
71  DUNE_THROW(NotImplemented, "You need to specialise the method istl_assign_to_fmatrix(DenseMatrix<M>& f, const T& t) "
72  << "(with M being " << className<M>() << ") "
73  << "for T == " << className<T>() << "!");
74  }
75 
76  namespace
77  {
78  template<bool b>
79  struct DenseMatrixAssigner
80  {
81  template<typename M, typename T>
82  static void assign(DenseMatrix<M>& fm, const T& t)
83  {
85  }
86 
87  };
88 
89 
90  template<>
91  struct DenseMatrixAssigner<true>
92  {
93  template<typename M, typename T>
94  static void assign(DenseMatrix<M>& fm, const T& t)
95  {
96  fm = static_cast<const typename DenseMatVecTraits<M>::value_type>(t);
97  }
98  };
99  }
100 
102  class FMatrixError : public Exception {};
103 
114  template<typename MAT>
116  {
118 
119  // Curiously recurring template pattern
120  MAT & asImp() { return static_cast<MAT&>(*this); }
121  const MAT & asImp() const { return static_cast<const MAT&>(*this); }
122 
123  public:
124  //===== type definitions and constants
125 
128 
130  typedef typename Traits::value_type value_type;
131 
133  typedef typename Traits::value_type field_type;
134 
136  typedef typename Traits::value_type block_type;
137 
139  typedef typename Traits::size_type size_type;
140 
142  typedef typename Traits::row_type row_type;
143 
146 
149 
151  enum {
154  };
155 
156  //===== access to components
157 
160  {
161  return asImp().mat_access(i);
162  }
163 
165  {
166  return asImp().mat_access(i);
167  }
168 
170  size_type size() const
171  {
172  return rows();
173  }
174 
175  //===== iterator interface to rows of the matrix
183  typedef typename row_type::Iterator ColIterator;
184 
187  {
188  return Iterator(*this,0);
189  }
190 
193  {
194  return Iterator(*this,rows());
195  }
196 
200  {
201  return Iterator(*this,rows()-1);
202  }
203 
207  {
208  return Iterator(*this,-1);
209  }
210 
219 
222  {
223  return ConstIterator(*this,0);
224  }
225 
228  {
229  return ConstIterator(*this,rows());
230  }
231 
235  {
236  return ConstIterator(*this,rows()-1);
237  }
238 
242  {
243  return ConstIterator(*this,-1);
244  }
245 
246  //===== assignment from scalar
248  {
249  for (size_type i=0; i<rows(); i++)
250  (*this)[i] = f;
251  return *this;
252  }
253 
254  template<typename T>
256  {
257  DenseMatrixAssigner<Conversion<T,field_type>::exists>::assign(*this, t);
258  return *this;
259  }
260  //===== vector space arithmetic
261 
263  template <class Other>
265  {
266  for (size_type i=0; i<rows(); i++)
267  (*this)[i] += y[i];
268  return *this;
269  }
270 
272  template <class Other>
274  {
275  for (size_type i=0; i<rows(); i++)
276  (*this)[i] -= y[i];
277  return *this;
278  }
279 
282  {
283  for (size_type i=0; i<rows(); i++)
284  (*this)[i] *= k;
285  return *this;
286  }
287 
290  {
291  for (size_type i=0; i<rows(); i++)
292  (*this)[i] /= k;
293  return *this;
294  }
295 
297  template <class Other>
299  {
300  for( size_type i = 0; i < rows(); ++i )
301  (*this)[ i ].axpy( k, y[ i ] );
302  return *this;
303  }
304 
306  template <class Other>
307  bool operator== (const DenseMatrix<Other>& y) const
308  {
309  for (size_type i=0; i<rows(); i++)
310  if ((*this)[i]!=y[i])
311  return false;
312  return true;
313  }
315  template <class Other>
316  bool operator!= (const DenseMatrix<Other>& y) const
317  {
318  return !operator==(y);
319  }
320 
321 
322  //===== linear maps
323 
325  template<class X, class Y>
326  void mv (const X& x, Y& y) const
327  {
328 #ifdef DUNE_FMatrix_WITH_CHECKING
329  if (x.N()!=M()) DUNE_THROW(FMatrixError,"Index out of range");
330  if (y.N()!=N()) DUNE_THROW(FMatrixError,"Index out of range");
331 #endif
332  for (size_type i=0; i<rows(); ++i)
333  {
334  y[i] = 0;
335  for (size_type j=0; j<cols(); j++)
336  y[i] += (*this)[i][j] * x[j];
337  }
338  }
339 
341  template< class X, class Y >
342  void mtv ( const X &x, Y &y ) const
343  {
344 #ifdef DUNE_FMatrix_WITH_CHECKING
345  //assert( &x != &y );
346  //This assert did not work for me. Compile error:
347  // comparison between distinct pointer types ‘const
348  // Dune::FieldVector<double, 3>*’ and ‘Dune::FieldVector<double, 2>*’ lacks a cast
349  if( x.N() != N() )
350  DUNE_THROW( FMatrixError, "Index out of range." );
351  if( y.N() != M() )
352  DUNE_THROW( FMatrixError, "Index out of range." );
353 #endif
354  for( size_type i = 0; i < cols(); ++i )
355  {
356  y[ i ] = 0;
357  for( size_type j = 0; j < rows(); ++j )
358  y[ i ] += (*this)[ j ][ i ] * x[ j ];
359  }
360  }
361 
363  template<class X, class Y>
364  void umv (const X& x, Y& y) const
365  {
366 #ifdef DUNE_FMatrix_WITH_CHECKING
367  if (x.N()!=M())
368  DUNE_THROW(FMatrixError,"y += A x -- index out of range (sizes: x: " << x.N() << ", y: " << y.N() << ", A: " << this->N() << " x " << this->M() << ")" << std::endl);
369  if (y.N()!=N())
370  DUNE_THROW(FMatrixError,"y += A x -- index out of range (sizes: x: " << x.N() << ", y: " << y.N() << ", A: " << this->N() << " x " << this->M() << ")" << std::endl);
371 #endif
372  for (size_type i=0; i<rows(); i++)
373  for (size_type j=0; j<cols(); j++)
374  y[i] += (*this)[i][j] * x[j];
375  }
376 
378  template<class X, class Y>
379  void umtv (const X& x, Y& y) const
380  {
381 #ifdef DUNE_FMatrix_WITH_CHECKING
382  if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
383  if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
384 #endif
385 
386  for (size_type i=0; i<rows(); i++)
387  for (size_type j=0; j<cols(); j++)
388  y[j] += (*this)[i][j]*x[i];
389  }
390 
392  template<class X, class Y>
393  void umhv (const X& x, Y& y) const
394  {
395 #ifdef DUNE_FMatrix_WITH_CHECKING
396  if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
397  if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
398 #endif
399 
400  for (size_type i=0; i<rows(); i++)
401  for (size_type j=0; j<cols(); j++)
402  y[j] += conjugateComplex((*this)[i][j])*x[i];
403  }
404 
406  template<class X, class Y>
407  void mmv (const X& x, Y& y) const
408  {
409 #ifdef DUNE_FMatrix_WITH_CHECKING
410  if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
411  if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
412 #endif
413  for (size_type i=0; i<rows(); i++)
414  for (size_type j=0; j<cols(); j++)
415  y[i] -= (*this)[i][j] * x[j];
416  }
417 
419  template<class X, class Y>
420  void mmtv (const X& x, Y& y) const
421  {
422 #ifdef DUNE_FMatrix_WITH_CHECKING
423  if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
424  if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
425 #endif
426 
427  for (size_type i=0; i<rows(); i++)
428  for (size_type j=0; j<cols(); j++)
429  y[j] -= (*this)[i][j]*x[i];
430  }
431 
433  template<class X, class Y>
434  void mmhv (const X& x, Y& y) const
435  {
436 #ifdef DUNE_FMatrix_WITH_CHECKING
437  if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
438  if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
439 #endif
440 
441  for (size_type i=0; i<rows(); i++)
442  for (size_type j=0; j<cols(); j++)
443  y[j] -= conjugateComplex((*this)[i][j])*x[i];
444  }
445 
447  template<class X, class Y>
448  void usmv (const field_type& alpha, const X& x, Y& y) const
449  {
450 #ifdef DUNE_FMatrix_WITH_CHECKING
451  if (x.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
452  if (y.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
453 #endif
454  for (size_type i=0; i<rows(); i++)
455  for (size_type j=0; j<cols(); j++)
456  y[i] += alpha * (*this)[i][j] * x[j];
457  }
458 
460  template<class X, class Y>
461  void usmtv (const field_type& alpha, const X& x, Y& y) const
462  {
463 #ifdef DUNE_FMatrix_WITH_CHECKING
464  if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
465  if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
466 #endif
467 
468  for (size_type i=0; i<rows(); i++)
469  for (size_type j=0; j<cols(); j++)
470  y[j] += alpha*(*this)[i][j]*x[i];
471  }
472 
474  template<class X, class Y>
475  void usmhv (const field_type& alpha, const X& x, Y& y) const
476  {
477 #ifdef DUNE_FMatrix_WITH_CHECKING
478  if (x.N()!=N()) DUNE_THROW(FMatrixError,"index out of range");
479  if (y.N()!=M()) DUNE_THROW(FMatrixError,"index out of range");
480 #endif
481 
482  for (size_type i=0; i<rows(); i++)
483  for (size_type j=0; j<cols(); j++)
484  y[j] += alpha*conjugateComplex((*this)[i][j])*x[i];
485  }
486 
487  //===== norms
488 
491  {
492  typename FieldTraits<value_type>::real_type sum=(0.0);
493  for (size_type i=0; i<rows(); ++i) sum += (*this)[i].two_norm2();
494  return fvmeta::sqrt(sum);
495  }
496 
499  {
500  typename FieldTraits<value_type>::real_type sum=(0.0);
501  for (size_type i=0; i<rows(); ++i) sum += (*this)[i].two_norm2();
502  return sum;
503  }
504 
507  {
509  for (size_type i=0; i<rows(); ++i) max = std::max(max,(*this)[i].one_norm());
510  return max;
511  }
512 
515  {
516  typename FieldTraits<value_type>::real_type max(0.0);
517  for (size_type i=0; i<rows(); ++i) max = std::max(max,(*this)[i].one_norm_real());
518  return max;
519  }
520 
521  //===== solve
522 
527  template <class V>
528  void solve (V& x, const V& b) const;
529 
534  void invert();
535 
537  field_type determinant () const;
538 
540  template<typename M2>
542  {
543  assert(M.rows() == M.cols() && M.rows() == rows());
544  MAT C(asImp());
545 
546  for (size_type i=0; i<rows(); i++)
547  for (size_type j=0; j<cols(); j++) {
548  (*this)[i][j] = 0;
549  for (size_type k=0; k<rows(); k++)
550  (*this)[i][j] += M[i][k]*C[k][j];
551  }
552 
553  return asImp();
554  }
555 
557  template<typename M2>
559  {
560  assert(M.rows() == M.cols() && M.cols() == cols());
561  MAT C(asImp());
562 
563  for (size_type i=0; i<rows(); i++)
564  for (size_type j=0; j<cols(); j++) {
565  (*this)[i][j] = 0;
566  for (size_type k=0; k<cols(); k++)
567  (*this)[i][j] += C[i][k]*M[k][j];
568  }
569  return asImp();
570  }
571 
572 #if 0
573 
574  template<int l>
575  DenseMatrix<K,l,cols> leftmultiplyany (const FieldMatrix<K,l,rows>& M) const
576  {
578 
579  for (size_type i=0; i<l; i++) {
580  for (size_type j=0; j<cols(); j++) {
581  C[i][j] = 0;
582  for (size_type k=0; k<rows(); k++)
583  C[i][j] += M[i][k]*(*this)[k][j];
584  }
585  }
586  return C;
587  }
588 
590  template<int l>
591  FieldMatrix<K,rows,l> rightmultiplyany (const FieldMatrix<K,cols,l>& M) const
592  {
593  FieldMatrix<K,rows,l> C;
594 
595  for (size_type i=0; i<rows(); i++) {
596  for (size_type j=0; j<l; j++) {
597  C[i][j] = 0;
598  for (size_type k=0; k<cols(); k++)
599  C[i][j] += (*this)[i][k]*M[k][j];
600  }
601  }
602  return C;
603  }
604 #endif
605 
606  //===== sizes
607 
609  size_type N () const
610  {
611  return rows();
612  }
613 
615  size_type M () const
616  {
617  return cols();
618  }
619 
621  size_type rows() const
622  {
623  return asImp().mat_rows();
624  }
625 
627  size_type cols() const
628  {
629  return asImp().mat_cols();
630  }
631 
632  //===== query
633 
635  bool exists (size_type i, size_type j) const
636  {
637 #ifdef DUNE_FMatrix_WITH_CHECKING
638  if (i<0 || i>=rows()) DUNE_THROW(FMatrixError,"row index out of range");
639  if (j<0 || j>=cols()) DUNE_THROW(FMatrixError,"column index out of range");
640 #endif
641  return true;
642  }
643 
644  private:
645 
646 #ifndef DOXYGEN
647  struct ElimPivot
648  {
649  ElimPivot(std::vector<size_type> & pivot);
650 
651  void swap(int i, int j);
652 
653  template<typename T>
654  void operator()(const T&, int k, int i)
655  {}
656 
657  std::vector<size_type> & pivot_;
658  };
659 
660  template<typename V>
661  struct Elim
662  {
663  Elim(V& rhs);
664 
665  void swap(int i, int j);
666 
667  void operator()(const typename V::field_type& factor, int k, int i);
668 
669  V* rhs_;
670  };
671 
672  struct ElimDet
673  {
674  ElimDet(field_type& sign) : sign_(sign)
675  { sign_ = 1; }
676 
677  void swap(int i, int j)
678  { sign_ *= -1; }
679 
680  void operator()(const field_type&, int k, int i)
681  {}
682 
683  field_type& sign_;
684  };
685 #endif // DOXYGEN
686 
687  template<class Func>
688  void luDecomposition(DenseMatrix<MAT>& A, Func func) const;
689  };
690 
691 #ifndef DOXYGEN
692  template<typename MAT>
693  DenseMatrix<MAT>::ElimPivot::ElimPivot(std::vector<size_type> & pivot)
694  : pivot_(pivot)
695  {
696  typedef typename std::vector<size_type>::size_type size_type;
697  for(size_type i=0; i < pivot_.size(); ++i) pivot_[i]=i;
698  }
699 
700  template<typename MAT>
701  void DenseMatrix<MAT>::ElimPivot::swap(int i, int j)
702  {
703  pivot_[i]=j;
704  }
705 
706  template<typename MAT>
707  template<typename V>
708  DenseMatrix<MAT>::Elim<V>::Elim(V& rhs)
709  : rhs_(&rhs)
710  {}
711 
712  template<typename MAT>
713  template<typename V>
714  void DenseMatrix<MAT>::Elim<V>::swap(int i, int j)
715  {
716  std::swap((*rhs_)[i], (*rhs_)[j]);
717  }
718 
719  template<typename MAT>
720  template<typename V>
721  void DenseMatrix<MAT>::
722  Elim<V>::operator()(const typename V::field_type& factor, int k, int i)
723  {
724  (*rhs_)[k] -= factor*(*rhs_)[i];
725  }
726  template<typename MAT>
727  template<typename Func>
728  inline void DenseMatrix<MAT>::luDecomposition(DenseMatrix<MAT>& A, Func func) const
729  {
730  typedef typename FieldTraits<value_type>::real_type
731  real_type;
732  real_type norm = A.infinity_norm_real(); // for relative thresholds
733  real_type pivthres = std::max( FMatrixPrecision< real_type >::absolute_limit(), norm * FMatrixPrecision< real_type >::pivoting_limit() );
734  real_type singthres = std::max( FMatrixPrecision< real_type >::absolute_limit(), norm * FMatrixPrecision< real_type >::singular_limit() );
735 
736  // LU decomposition of A in A
737  for (size_type i=0; i<rows(); i++) // loop over all rows
738  {
739  typename FieldTraits<value_type>::real_type pivmax=fvmeta::absreal(A[i][i]);
740 
741  // pivoting ?
742  if (pivmax<pivthres)
743  {
744  // compute maximum of column
745  size_type imax=i;
746  typename FieldTraits<value_type>::real_type abs(0.0);
747  for (size_type k=i+1; k<rows(); k++)
748  if ((abs=fvmeta::absreal(A[k][i]))>pivmax)
749  {
750  pivmax = abs; imax = k;
751  }
752  // swap rows
753  if (imax!=i){
754  for (size_type j=0; j<rows(); j++)
755  std::swap(A[i][j],A[imax][j]);
756  func.swap(i, imax); // swap the pivot or rhs
757  }
758  }
759 
760  // singular ?
761  if (pivmax<singthres)
762  DUNE_THROW(FMatrixError,"matrix is singular");
763 
764  // eliminate
765  for (size_type k=i+1; k<rows(); k++)
766  {
767  field_type factor = A[k][i]/A[i][i];
768  A[k][i] = factor;
769  for (size_type j=i+1; j<rows(); j++)
770  A[k][j] -= factor*A[i][j];
771  func(factor, k, i);
772  }
773  }
774  }
775 
776  template<typename MAT>
777  template <class V>
778  inline void DenseMatrix<MAT>::solve(V& x, const V& b) const
779  {
780  // never mind those ifs, because they get optimized away
781  if (rows()!=cols())
782  DUNE_THROW(FMatrixError, "Can't solve for a " << rows() << "x" << cols() << " matrix!");
783 
784  if (rows()==1) {
785 
786 #ifdef DUNE_FMatrix_WITH_CHECKING
787  if (fvmeta::absreal((*this)[0][0])<FMatrixPrecision<>::absolute_limit())
788  DUNE_THROW(FMatrixError,"matrix is singular");
789 #endif
790  x[0] = b[0]/(*this)[0][0];
791 
792  }
793  else if (rows()==2) {
794 
795  field_type detinv = (*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0];
796 #ifdef DUNE_FMatrix_WITH_CHECKING
797  if (fvmeta::absreal(detinv)<FMatrixPrecision<>::absolute_limit())
798  DUNE_THROW(FMatrixError,"matrix is singular");
799 #endif
800  detinv = 1.0/detinv;
801 
802  x[0] = detinv*((*this)[1][1]*b[0]-(*this)[0][1]*b[1]);
803  x[1] = detinv*((*this)[0][0]*b[1]-(*this)[1][0]*b[0]);
804 
805  }
806  else if (rows()==3) {
807 
808  field_type d = determinant();
809 #ifdef DUNE_FMatrix_WITH_CHECKING
810  if (fvmeta::absreal(d)<FMatrixPrecision<>::absolute_limit())
811  DUNE_THROW(FMatrixError,"matrix is singular");
812 #endif
813 
814  x[0] = (b[0]*(*this)[1][1]*(*this)[2][2] - b[0]*(*this)[2][1]*(*this)[1][2]
815  - b[1] *(*this)[0][1]*(*this)[2][2] + b[1]*(*this)[2][1]*(*this)[0][2]
816  + b[2] *(*this)[0][1]*(*this)[1][2] - b[2]*(*this)[1][1]*(*this)[0][2]) / d;
817 
818  x[1] = ((*this)[0][0]*b[1]*(*this)[2][2] - (*this)[0][0]*b[2]*(*this)[1][2]
819  - (*this)[1][0] *b[0]*(*this)[2][2] + (*this)[1][0]*b[2]*(*this)[0][2]
820  + (*this)[2][0] *b[0]*(*this)[1][2] - (*this)[2][0]*b[1]*(*this)[0][2]) / d;
821 
822  x[2] = ((*this)[0][0]*(*this)[1][1]*b[2] - (*this)[0][0]*(*this)[2][1]*b[1]
823  - (*this)[1][0] *(*this)[0][1]*b[2] + (*this)[1][0]*(*this)[2][1]*b[0]
824  + (*this)[2][0] *(*this)[0][1]*b[1] - (*this)[2][0]*(*this)[1][1]*b[0]) / d;
825 
826  }
827  else {
828 
829  V& rhs = x; // use x to store rhs
830  rhs = b; // copy data
831  Elim<V> elim(rhs);
832  MAT A(asImp());
833 
834  luDecomposition(A, elim);
835 
836  // backsolve
837  for(int i=rows()-1; i>=0; i--){
838  for (size_type j=i+1; j<rows(); j++)
839  rhs[i] -= A[i][j]*x[j];
840  x[i] = rhs[i]/A[i][i];
841  }
842  }
843  }
844 
845  template<typename MAT>
846  inline void DenseMatrix<MAT>::invert()
847  {
848  // never mind those ifs, because they get optimized away
849  if (rows()!=cols())
850  DUNE_THROW(FMatrixError, "Can't invert a " << rows() << "x" << cols() << " matrix!");
851 
852  if (rows()==1) {
853 
854 #ifdef DUNE_FMatrix_WITH_CHECKING
855  if (fvmeta::absreal((*this)[0][0])<FMatrixPrecision<>::absolute_limit())
856  DUNE_THROW(FMatrixError,"matrix is singular");
857 #endif
858  (*this)[0][0] = 1.0/(*this)[0][0];
859 
860  }
861  else if (rows()==2) {
862 
863  field_type detinv = (*this)[0][0]*(*this)[1][1]-(*this)[0][1]*(*this)[1][0];
864 #ifdef DUNE_FMatrix_WITH_CHECKING
865  if (fvmeta::absreal(detinv)<FMatrixPrecision<>::absolute_limit())
866  DUNE_THROW(FMatrixError,"matrix is singular");
867 #endif
868  detinv = 1.0/detinv;
869 
870  field_type temp=(*this)[0][0];
871  (*this)[0][0] = (*this)[1][1]*detinv;
872  (*this)[0][1] = -(*this)[0][1]*detinv;
873  (*this)[1][0] = -(*this)[1][0]*detinv;
874  (*this)[1][1] = temp*detinv;
875 
876  }
877  else {
878 
879  MAT A(asImp());
880  std::vector<size_type> pivot(rows());
881  luDecomposition(A, ElimPivot(pivot));
882  DenseMatrix<MAT>& L=A;
883  DenseMatrix<MAT>& U=A;
884 
885  // initialize inverse
886  *this=field_type();
887 
888  for(size_type i=0; i<rows(); ++i)
889  (*this)[i][i]=1;
890 
891  // L Y = I; multiple right hand sides
892  for (size_type i=0; i<rows(); i++)
893  for (size_type j=0; j<i; j++)
894  for (size_type k=0; k<rows(); k++)
895  (*this)[i][k] -= L[i][j]*(*this)[j][k];
896 
897  // U A^{-1} = Y
898  for (size_type i=rows(); i>0;){
899  --i;
900  for (size_type k=0; k<rows(); k++){
901  for (size_type j=i+1; j<rows(); j++)
902  (*this)[i][k] -= U[i][j]*(*this)[j][k];
903  (*this)[i][k] /= U[i][i];
904  }
905  }
906 
907  for(size_type i=rows(); i>0; ){
908  --i;
909  if(i!=pivot[i])
910  for(size_type j=0; j<rows(); ++j)
911  std::swap((*this)[j][pivot[i]], (*this)[j][i]);
912  }
913  }
914  }
915 
916  // implementation of the determinant
917  template<typename MAT>
918  inline typename DenseMatrix<MAT>::field_type
919  DenseMatrix<MAT>::determinant() const
920  {
921  // never mind those ifs, because they get optimized away
922  if (rows()!=cols())
923  DUNE_THROW(FMatrixError, "There is no determinant for a " << rows() << "x" << cols() << " matrix!");
924 
925  if (rows()==1)
926  return (*this)[0][0];
927 
928  if (rows()==2)
929  return (*this)[0][0]*(*this)[1][1] - (*this)[0][1]*(*this)[1][0];
930 
931  if (rows()==3) {
932  // code generated by maple
933  field_type t4 = (*this)[0][0] * (*this)[1][1];
934  field_type t6 = (*this)[0][0] * (*this)[1][2];
935  field_type t8 = (*this)[0][1] * (*this)[1][0];
936  field_type t10 = (*this)[0][2] * (*this)[1][0];
937  field_type t12 = (*this)[0][1] * (*this)[2][0];
938  field_type t14 = (*this)[0][2] * (*this)[2][0];
939 
940  return (t4*(*this)[2][2]-t6*(*this)[2][1]-t8*(*this)[2][2]+
941  t10*(*this)[2][1]+t12*(*this)[1][2]-t14*(*this)[1][1]);
942 
943  }
944 
945  MAT A(asImp());
946  field_type det;
947  try
948  {
949  luDecomposition(A, ElimDet(det));
950  }
951  catch (FMatrixError&)
952  {
953  return 0;
954  }
955  for (size_type i = 0; i < rows(); ++i)
956  det *= A[i][i];
957  return det;
958  }
959 
960 #endif // DOXYGEN
961 
962  namespace DenseMatrixHelp {
963 #if 0
964 
965  template <typename K>
966  static inline K invertMatrix (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
967  {
968  inverse[0][0] = 1.0/matrix[0][0];
969  return matrix[0][0];
970  }
971 
973  template <typename K>
974  static inline K invertMatrix_retTransposed (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
975  {
976  return invertMatrix(matrix,inverse);
977  }
978 
979 
981  template <typename K>
982  static inline K invertMatrix (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
983  {
984  // code generated by maple
985  field_type det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
986  field_type det_1 = 1.0/det;
987  inverse[0][0] = matrix[1][1] * det_1;
988  inverse[0][1] = - matrix[0][1] * det_1;
989  inverse[1][0] = - matrix[1][0] * det_1;
990  inverse[1][1] = matrix[0][0] * det_1;
991  return det;
992  }
993 
996  template <typename K>
997  static inline K invertMatrix_retTransposed (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
998  {
999  // code generated by maple
1000  field_type det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
1001  field_type det_1 = 1.0/det;
1002  inverse[0][0] = matrix[1][1] * det_1;
1003  inverse[1][0] = - matrix[0][1] * det_1;
1004  inverse[0][1] = - matrix[1][0] * det_1;
1005  inverse[1][1] = matrix[0][0] * det_1;
1006  return det;
1007  }
1008 
1010  template <typename K>
1011  static inline K invertMatrix (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
1012  {
1013  // code generated by maple
1014  field_type t4 = matrix[0][0] * matrix[1][1];
1015  field_type t6 = matrix[0][0] * matrix[1][2];
1016  field_type t8 = matrix[0][1] * matrix[1][0];
1017  field_type t10 = matrix[0][2] * matrix[1][0];
1018  field_type t12 = matrix[0][1] * matrix[2][0];
1019  field_type t14 = matrix[0][2] * matrix[2][0];
1020 
1021  field_type det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
1022  t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
1023  field_type t17 = 1.0/det;
1024 
1025  inverse[0][0] = (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
1026  inverse[0][1] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
1027  inverse[0][2] = (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
1028  inverse[1][0] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
1029  inverse[1][1] = (matrix[0][0] * matrix[2][2] - t14) * t17;
1030  inverse[1][2] = -(t6-t10) * t17;
1031  inverse[2][0] = (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
1032  inverse[2][1] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
1033  inverse[2][2] = (t4-t8) * t17;
1034 
1035  return det;
1036  }
1037 
1039  template <typename K>
1040  static inline K invertMatrix_retTransposed (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
1041  {
1042  // code generated by maple
1043  field_type t4 = matrix[0][0] * matrix[1][1];
1044  field_type t6 = matrix[0][0] * matrix[1][2];
1045  field_type t8 = matrix[0][1] * matrix[1][0];
1046  field_type t10 = matrix[0][2] * matrix[1][0];
1047  field_type t12 = matrix[0][1] * matrix[2][0];
1048  field_type t14 = matrix[0][2] * matrix[2][0];
1049 
1050  field_type det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+
1051  t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]);
1052  field_type t17 = 1.0/det;
1053 
1054  inverse[0][0] = (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
1055  inverse[1][0] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
1056  inverse[2][0] = (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
1057  inverse[0][1] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
1058  inverse[1][1] = (matrix[0][0] * matrix[2][2] - t14) * t17;
1059  inverse[2][1] = -(t6-t10) * t17;
1060  inverse[0][2] = (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
1061  inverse[1][2] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
1062  inverse[2][2] = (t4-t8) * t17;
1063 
1064  return det;
1065  }
1066 
1068  template< class K, int m, int n, int p >
1069  static inline void multMatrix ( const FieldMatrix< K, m, n > &A,
1070  const FieldMatrix< K, n, p > &B,
1071  FieldMatrix< K, m, p > &ret )
1072  {
1073  typedef typename FieldMatrix< K, m, p > :: size_type size_type;
1074 
1075  for( size_type i = 0; i < m; ++i )
1076  {
1077  for( size_type j = 0; j < p; ++j )
1078  {
1079  ret[ i ][ j ] = K( 0 );
1080  for( size_type k = 0; k < n; ++k )
1081  ret[ i ][ j ] += A[ i ][ k ] * B[ k ][ j ];
1082  }
1083  }
1084  }
1085 
1087  template <typename K, int rows, int cols>
1088  static inline void multTransposedMatrix(const FieldMatrix<K,rows,cols> &matrix, FieldMatrix<K,cols,cols>& ret)
1089  {
1090  typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
1091 
1092  for(size_type i=0; i<cols(); i++)
1093  for(size_type j=0; j<cols(); j++)
1094  {
1095  ret[i][j]=0.0;
1096  for(size_type k=0; k<rows(); k++)
1097  ret[i][j]+=matrix[k][i]*matrix[k][j];
1098  }
1099  }
1100 #endif
1101 
1103  template <typename MAT, typename V1, typename V2>
1104  static inline void multAssign(const DenseMatrix<MAT> &matrix, const DenseVector<V1> & x, DenseVector<V2> & ret)
1105  {
1106  assert(x.size() == matrix.cols());
1107  assert(ret.size() == matrix.rows());
1108  typedef typename DenseMatrix<MAT>::size_type size_type;
1109 
1110  for(size_type i=0; i<matrix.rows(); ++i)
1111  {
1112  ret[i] = 0.0;
1113  for(size_type j=0; j<matrix.cols(); ++j)
1114  {
1115  ret[i] += matrix[i][j]*x[j];
1116  }
1117  }
1118  }
1119 
1120 #if 0
1121 
1122  template <typename K, int rows, int cols>
1123  static inline void multAssignTransposed( const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x, FieldVector<K,cols> & ret)
1124  {
1125  typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
1126 
1127  for(size_type i=0; i<cols(); ++i)
1128  {
1129  ret[i] = 0.0;
1130  for(size_type j=0; j<rows(); ++j)
1131  ret[i] += matrix[j][i]*x[j];
1132  }
1133  }
1134 
1136  template <typename K, int rows, int cols>
1137  static inline FieldVector<K,rows> mult(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x)
1138  {
1139  FieldVector<K,rows> ret;
1140  multAssign(matrix,x,ret);
1141  return ret;
1142  }
1143 
1145  template <typename K, int rows, int cols>
1146  static inline FieldVector<K,cols> multTransposed(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x)
1147  {
1148  FieldVector<K,cols> ret;
1149  multAssignTransposed( matrix, x, ret );
1150  return ret;
1151  }
1152 #endif
1153 
1154  } // end namespace DenseMatrixHelp
1155 
1157  template<typename MAT>
1158  std::ostream& operator<< (std::ostream& s, const DenseMatrix<MAT>& a)
1159  {
1160  for (typename DenseMatrix<MAT>::size_type i=0; i<a.rows(); i++)
1161  s << a[i] << std::endl;
1162  return s;
1163  }
1164 
1167 } // end namespace Dune
1168 
1169 #endif