diff --git a/common/fmatrix.hh b/common/fmatrix.hh index 91a35cf17831b2a091ecf2d2217e3a45dfbed283..aa9bcbfd63a378829710f7fc0c8ec1121b61d92e 100644 --- a/common/fmatrix.hh +++ b/common/fmatrix.hh @@ -44,193 +44,6 @@ namespace Dune { return std::complex<K>(c.real(),-c.imag()); } - - //! solve small system - template<class K, int n, class V> - void fm_solve (const FieldMatrix<K,n,n>& Ain, V& x, const V& b) - { - // make a copy of a to store factorization - FieldMatrix<K,n,n> A(Ain); - - // Gaussian elimination with maximum column pivot - double norm=A.infinity_norm_real(); // for relative thresholds - double pivthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::pivoting_limit()); - double singthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::singular_limit()); - V& rhs = x; // use x to store rhs - rhs = b; // copy data - - // elimination phase - for (int i=0; i<n; i++) // loop over all rows - { - double pivmax=fvmeta_absreal(A[i][i]); - - // pivoting ? - if (pivmax<pivthres) - { - // compute maximum of row - int imax=i; double abs; - for (int k=i+1; k<n; k++) - if ((abs=fvmeta_absreal(A[k][i]))>pivmax) - { - pivmax = abs; imax = k; - } - // swap rows - if (imax!=i) - for (int j=i; j<n; j++) - std::swap(A[i][j],A[imax][j]); - } - - // singular ? - if (pivmax<singthres) - DUNE_THROW(FMatrixError,"matrix is singular"); - - // eliminate - for (int k=i+1; k<n; k++) - { - K factor = -A[k][i]/A[i][i]; - for (int j=i+1; j<n; j++) - A[k][j] += factor*A[i][j]; - rhs[k] += factor*rhs[i]; - } - } - - // backsolve - for (int i=n-1; i>=0; i--) - { - for (int j=i+1; j<n; j++) - rhs[i] -= A[i][j]*x[j]; - x[i] = rhs[i]/A[i][i]; - } - } - - //! special case for 1x1 matrix, x and b may be identical - template<class K, class V> - inline void fm_solve (const FieldMatrix<K,1,1>& A, V& x, const V& b) - { -#ifdef DUNE_FMatrix_WITH_CHECKING - if (fvmeta_absreal(A[0][0])<FMatrixPrecision<>::absolute_limit()) - DUNE_THROW(FMatrixError,"matrix is singular"); -#endif - x[0] = b[0]/A[0][0]; - } - - //! special case for 2x2 matrix, x and b may be identical - template<class K, class V> - inline void fm_solve (const FieldMatrix<K,2,2>& A, V& x, const V& b) - { -#ifdef DUNE_FMatrix_WITH_CHECKING - K detinv = A[0][0]*A[1][1]-A[0][1]*A[1][0]; - if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit()) - DUNE_THROW(FMatrixError,"matrix is singular"); - detinv = 1/detinv; -#else - K detinv = 1.0/(A[0][0]*A[1][1]-A[0][1]*A[1][0]); -#endif - - K temp = b[0]; - x[0] = detinv*(A[1][1]*b[0]-A[0][1]*b[1]); - x[1] = detinv*(A[0][0]*b[1]-A[1][0]*temp); - } - - - - //! compute inverse - template<class K, int n> - void fm_invert (FieldMatrix<K,n,n>& B) - { - FieldMatrix<K,n,n> A(B); - FieldMatrix<K,n,n>& L=A; - FieldMatrix<K,n,n>& U=A; - - double norm=A.infinity_norm_real(); // for relative thresholds - double pivthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::pivoting_limit()); - double singthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::singular_limit()); - - // LU decomposition of A in A - for (int i=0; i<n; i++) // loop over all rows - { - double pivmax=fvmeta_absreal(A[i][i]); - - // pivoting ? - if (pivmax<pivthres) - { - // compute maximum of column - int imax=i; double abs; - for (int k=i+1; k<n; k++) - if ((abs=fvmeta_absreal(A[k][i]))>pivmax) - { - pivmax = abs; imax = k; - } - // swap rows - if (imax!=i) - for (int j=i; j<n; j++) - std::swap(A[i][j],A[imax][j]); - } - - // singular ? - if (pivmax<singthres) - DUNE_THROW(FMatrixError,"matrix is singular"); - - // eliminate - for (int k=i+1; k<n; k++) - { - K factor = A[k][i]/A[i][i]; - L[k][i] = factor; - for (int j=i+1; j<n; j++) - A[k][j] -= factor*A[i][j]; - } - } - - // initialize inverse - B = 0; - for (int i=0; i<n; i++) B[i][i] = 1; - - // L Y = I; multiple right hand sides - for (int i=0; i<n; i++) - for (int j=0; j<i; j++) - for (int k=0; k<n; k++) - B[i][k] -= L[i][j]*B[j][k]; - - // U A^{-1} = Y - for (int i=n-1; i>=0; i--) - for (int k=0; k<n; k++) - { - for (int j=i+1; j<n; j++) - B[i][k] -= U[i][j]*B[j][k]; - B[i][k] /= U[i][i]; - } - } - - //! compute inverse n=1 - template<class K> - void fm_invert (FieldMatrix<K,1,1>& A) - { -#ifdef DUNE_FMatrix_WITH_CHECKING - if (fvmeta_absreal(A[0][0])<FMatrixPrecision<>::absolute_limit()) - DUNE_THROW(FMatrixError,"matrix is singular"); -#endif - A[0][0] = 1/A[0][0]; - } - - //! compute inverse n=2 - template<class K> - void fm_invert (FieldMatrix<K,2,2>& A) - { - K detinv = A[0][0]*A[1][1]-A[0][1]*A[1][0]; -#ifdef DUNE_FMatrix_WITH_CHECKING - if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit()) - DUNE_THROW(FMatrixError,"matrix is singular"); -#endif - detinv = 1/detinv; - - K temp=A[0][0]; - A[0][0] = A[1][1]*detinv; - A[0][1] = -A[0][1]*detinv; - A[1][0] = -A[1][0]*detinv; - A[1][1] = temp*detinv; - } - - /** @brief A dense n x m matrix. @@ -588,19 +401,13 @@ namespace Dune { * \exception FMatrixError if the matrix is singular */ template<class V> - void solve (V& x, const V& b) const - { - fm_solve(*this,x,b); - } + void solve (V& x, const V& b) const; /** \brief Compute inverse * * \exception FMatrixError if the matrix is singular */ - void invert () - { - fm_invert(*this); - } + void invert(); //! calculates the determinant of this matrix K determinant () const; @@ -700,57 +507,217 @@ namespace Dune { row_type p[(n > 0) ? n : 1]; }; + template <class K, int n, int m> + template <class V> + inline void FieldMatrix<K,n,m>::solve(V& x, const V& b) const + { + // never mind those ifs, because they get optimized away + if (n!=m) + DUNE_THROW(FMatrixError, "Can't solve for a " << n << "x" << m << " matrix!"); - namespace HelpMat { + // no need to implement the case 1x1, because the whole matrix class is + // specialized for this - // calculation of determinat of matrix - template <class K, int row,int col> - static inline K determinantMatrix (const FieldMatrix<K,row,col> &matrix) - { - if (row!=col) - DUNE_THROW(FMatrixError, "There is no determinant for a " << row << "x" << col << " matrix!"); + if (n==2) { - DUNE_THROW(FMatrixError, "No implementation of determinantMatrix " - << "for FieldMatrix<" << row << "," << col << "> !"); +#ifdef DUNE_FMatrix_WITH_CHECKING + K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0]; + if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit()) + DUNE_THROW(FMatrixError,"matrix is singular"); + detinv = 1/detinv; +#else + K detinv = 1.0/(p[0][0]*p[1][1]-p[0][1]*p[1][0]); +#endif - return 0.0; - } + x[0] = detinv*(p[1][1]*b[0]-p[0][1]*b[1]); + x[1] = detinv*(p[0][0]*b[1]-p[1][0]*b[0]); - template <typename K> - static inline K determinantMatrix (const FieldMatrix<K,1,1> &matrix) - { - return matrix[0][0]; - } + } else { + + // //////////////////////////////////////////////////// + // Gaussian elimination with maximum column pivot + // //////////////////////////////////////////////////// + + // make a copy of a to store factorization + FieldMatrix<K,n,n> A(*this); + + double norm=A.infinity_norm_real(); // for relative thresholds + double pivthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::pivoting_limit()); + double singthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::singular_limit()); + V& rhs = x; // use x to store rhs + rhs = b; // copy data + + // elimination phase + for (int i=0; i<n; i++) // loop over all rows + { + double pivmax=fvmeta_absreal(A[i][i]); + + // pivoting ? + if (pivmax<pivthres) + { + // compute maximum of row + int imax=i; double abs; + for (int k=i+1; k<n; k++) + if ((abs=fvmeta_absreal(A[k][i]))>pivmax) + { + pivmax = abs; imax = k; + } + // swap rows + if (imax!=i) + for (int j=i; j<n; j++) + std::swap(A[i][j],A[imax][j]); + } + + // singular ? + if (pivmax<singthres) + DUNE_THROW(FMatrixError,"matrix is singular"); + + // eliminate + for (int k=i+1; k<n; k++) + { + K factor = -A[k][i]/A[i][i]; + for (int j=i+1; j<n; j++) + A[k][j] += factor*A[i][j]; + rhs[k] += factor*rhs[i]; + } + } + + // backsolve + for (int i=n-1; i>=0; i--) + { + for (int j=i+1; j<n; j++) + rhs[i] -= A[i][j]*x[j]; + x[i] = rhs[i]/A[i][i]; + } - template <typename K> - static inline K determinantMatrix (const FieldMatrix<K,2,2> &matrix) - { - return matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]; } - template <typename K> - static inline K determinantMatrix (const FieldMatrix<K,3,3> &matrix) - { - // code generated by maple - K t4 = matrix[0][0] * matrix[1][1]; - K t6 = matrix[0][0] * matrix[1][2]; - K t8 = matrix[0][1] * matrix[1][0]; - K t10 = matrix[0][2] * matrix[1][0]; - K t12 = matrix[0][1] * matrix[2][0]; - K t14 = matrix[0][2] * matrix[2][0]; + } + + template <class K, int n, int m> + inline void FieldMatrix<K,n,m>::invert() + { + // never mind those ifs, because they get optimized away + if (n!=m) + DUNE_THROW(FMatrixError, "Can't invert a " << n << "x" << m << " matrix!"); + + // no need to implement the case 1x1, because the whole matrix class is + // specialized for this + + if (n==2) { + + K detinv = p[0][0]*p[1][1]-p[0][1]*p[1][0]; +#ifdef DUNE_FMatrix_WITH_CHECKING + if (fvmeta_absreal(detinv)<FMatrixPrecision<>::absolute_limit()) + DUNE_THROW(FMatrixError,"matrix is singular"); +#endif + detinv = 1/detinv; + + K temp=p[0][0]; + p[0][0] = p[1][1]*detinv; + p[0][1] = -p[0][1]*detinv; + p[1][0] = -p[1][0]*detinv; + p[1][1] = temp*detinv; + + } else { + + FieldMatrix<K,n,n> A(*this); + FieldMatrix<K,n,n>& L=A; + FieldMatrix<K,n,n>& U=A; + + double norm=A.infinity_norm_real(); // for relative thresholds + double pivthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::pivoting_limit()); + double singthres = std::max(FMatrixPrecision<>::absolute_limit(),norm*FMatrixPrecision<>::singular_limit()); + + // LU decomposition of A in A + for (int i=0; i<n; i++) // loop over all rows + { + double pivmax=fvmeta_absreal(A[i][i]); + + // pivoting ? + if (pivmax<pivthres) + { + // compute maximum of column + int imax=i; double abs; + for (int k=i+1; k<n; k++) + if ((abs=fvmeta_absreal(A[k][i]))>pivmax) + { + pivmax = abs; imax = k; + } + // swap rows + if (imax!=i) + for (int j=i; j<n; j++) + std::swap(A[i][j],A[imax][j]); + } + + // singular ? + if (pivmax<singthres) + DUNE_THROW(FMatrixError,"matrix is singular"); + + // eliminate + for (int k=i+1; k<n; k++) + { + K factor = A[k][i]/A[i][i]; + L[k][i] = factor; + for (int j=i+1; j<n; j++) + A[k][j] -= factor*A[i][j]; + } + } + + // initialize inverse + *this = 0; + for (int i=0; i<n; i++) p[i][i] = 1; + + // L Y = I; multiple right hand sides + for (int i=0; i<n; i++) + for (int j=0; j<i; j++) + for (int k=0; k<n; k++) + p[i][k] -= L[i][j]*p[j][k]; + + // U A^{-1} = Y + for (int i=n-1; i>=0; i--) + for (int k=0; k<n; k++) + { + for (int j=i+1; j<n; j++) + p[i][k] -= U[i][j]*p[j][k]; + p[i][k] /= U[i][i]; + } - K det = (t4*matrix[2][2]-t6*matrix[2][1]-t8*matrix[2][2]+ - t10*matrix[2][1]+t12*matrix[1][2]-t14*matrix[1][1]); - return det; } - } // end namespace HelpMat + } // implementation of the determinant template <class K, int n, int m> - inline K FieldMatrix<K,n,m>::determinant () const + inline K FieldMatrix<K,n,m>::determinant() const { - return HelpMat::determinantMatrix(*this); + // never mind those ifs, because they get optimized away + if (n!=m) + DUNE_THROW(FMatrixError, "There is no determinant for a " << n << "x" << m << " matrix!"); + + // no need to implement the case 1x1, because the whole matrix class is + // specialized for this + + if (n==2) + return p[0][0]*p[1][1] - p[0][1]*p[1][0]; + + if (n==3) { + // code generated by maple + K t4 = p[0][0] * p[1][1]; + K t6 = p[0][0] * p[1][2]; + K t8 = p[0][1] * p[1][0]; + K t10 = p[0][2] * p[1][0]; + K t12 = p[0][1] * p[2][0]; + K t14 = p[0][2] * p[2][0]; + + return (t4*p[2][2]-t6*p[2][1]-t8*p[2][2]+ + t10*p[2][1]+t12*p[1][2]-t14*p[1][1]); + + } + + DUNE_THROW(FMatrixError, "No implementation of determinantMatrix " + << "for FieldMatrix<" << n << "," << m << "> !"); + } @@ -1019,12 +986,20 @@ namespace Dune { //! Solve system A x = b void solve (FieldVector<K,1>& x, const FieldVector<K,1>& b) const { +#ifdef DUNE_FMatrix_WITH_CHECKING + if (fvmeta_absreal(a[0][0])<FMatrixPrecision<>::absolute_limit()) + DUNE_THROW(FMatrixError,"matrix is singular"); +#endif x.p = b.p/a[0]; } //! compute inverse void invert () { +#ifdef DUNE_FMatrix_WITH_CHECKING + if (fvmeta_absreal(a[0][0])<FMatrixPrecision<>::absolute_limit()) + DUNE_THROW(FMatrixError,"matrix is singular"); +#endif a[0] = 1/a[0]; }