From a70c8d2d6afdfa95b8e15cd19abce9cb5f1e75a0 Mon Sep 17 00:00:00 2001 From: Oliver Sander <sander@dune-project.org> Date: Mon, 14 Feb 2005 08:48:41 +0000 Subject: [PATCH] moved here from istl [[Imported from SVN: r1466]] --- common/fmatrix.hh | 1349 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1349 insertions(+) create mode 100644 common/fmatrix.hh diff --git a/common/fmatrix.hh b/common/fmatrix.hh new file mode 100644 index 000000000..81efa001f --- /dev/null +++ b/common/fmatrix.hh @@ -0,0 +1,1349 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_FMATRIX_HH +#define DUNE_FMATRIX_HH + +#include <math.h> +#include <complex> +#include <iostream> + +#include <dune/istl/istlexception.hh> +#include <dune/istl/allocator.hh> +#include <dune/common/fvector.hh> +#include <dune/istl/precision.hh> + +/*! \file + + \brief This file implements a matrix constructed from a given type + representing a field and compile-time given number of rows and columns. + */ + +namespace Dune { + + /** + @addtogroup ISTL + @ingroup Common + @{ + */ + + template<class K, int n, int m> class FieldMatrix; + + // template meta program for assignment from scalar + template<int I> + struct fmmeta_assignscalar { + template<class T, class K> + static void assignscalar (T* x, const K& k) + { + fmmeta_assignscalar<I-1>::assignscalar(x,k); + x[I] = k; + } + }; + template<> + struct fmmeta_assignscalar<0> { + template<class T, class K> + static void assignscalar (T* x, const K& k) + { + x[0] = k; + } + }; + + // template meta program for operator+= + template<int I> + struct fmmeta_plusequal { + template<class T> + static void plusequal (T& x, const T& y) + { + x[I] += y[I]; + fmmeta_plusequal<I-1>::plusequal(x,y); + } + }; + template<> + struct fmmeta_plusequal<0> { + template<class T> + static void plusequal (T& x, const T& y) + { + x[0] += y[0]; + } + }; + + // template meta program for operator-= + template<int I> + struct fmmeta_minusequal { + template<class T> + static void minusequal (T& x, const T& y) + { + x[I] -= y[I]; + fmmeta_minusequal<I-1>::minusequal(x,y); + } + }; + template<> + struct fmmeta_minusequal<0> { + template<class T> + static void minusequal (T& x, const T& y) + { + x[0] -= y[0]; + } + }; + + // template meta program for operator*= + template<int I> + struct fmmeta_multequal { + template<class T, class K> + static void multequal (T& x, const K& k) + { + x[I] *= k; + fmmeta_multequal<I-1>::multequal(x,k); + } + }; + template<> + struct fmmeta_multequal<0> { + template<class T, class K> + static void multequal (T& x, const K& k) + { + x[0] *= k; + } + }; + + // template meta program for operator/= + template<int I> + struct fmmeta_divequal { + template<class T, class K> + static void divequal (T& x, const K& k) + { + x[I] /= k; + fmmeta_divequal<I-1>::divequal(x,k); + } + }; + template<> + struct fmmeta_divequal<0> { + template<class T, class K> + static void divequal (T& x, const K& k) + { + x[0] /= k; + } + }; + + // template meta program for dot + template<int I> + struct fmmeta_dot { + template<class X, class Y, class K> + static K dot (const X& x, const Y& y) + { + return x[I]*y[I] + fmmeta_dot<I-1>::template dot<X,Y,K>(x,y); + } + }; + template<> + struct fmmeta_dot<0> { + template<class X, class Y, class K> + static K dot (const X& x, const Y& y) + { + return x[0]*y[0]; + } + }; + + // template meta program for umv(x,y) + template<int I> + struct fmmeta_umv { + template<class Mat, class X, class Y, int c> + static void umv (const Mat& A, const X& x, Y& y) + { + typedef typename Mat::row_type R; + typedef typename Mat::field_type K; + y[I] += fmmeta_dot<c>::template dot<R,X,K>(A[I],x); + fmmeta_umv<I-1>::template umv<Mat,X,Y,c>(A,x,y); + } + }; + template<> + struct fmmeta_umv<0> { + template<class Mat, class X, class Y, int c> + static void umv (const Mat& A, const X& x, Y& y) + { + typedef typename Mat::row_type R; + typedef typename Mat::field_type K; + y[0] += fmmeta_dot<c>::template dot<R,X,K>(A[0],x); + } + }; + + // template meta program for mmv(x,y) + template<int I> + struct fmmeta_mmv { + template<class Mat, class X, class Y, int c> + static void mmv (const Mat& A, const X& x, Y& y) + { + typedef typename Mat::row_type R; + typedef typename Mat::field_type K; + y[I] -= fmmeta_dot<c>::template dot<R,X,K>(A[I],x); + fmmeta_mmv<I-1>::template mmv<Mat,X,Y,c>(A,x,y); + } + }; + template<> + struct fmmeta_mmv<0> { + template<class Mat, class X, class Y, int c> + static void mmv (const Mat& A, const X& x, Y& y) + { + typedef typename Mat::row_type R; + typedef typename Mat::field_type K; + y[0] -= fmmeta_dot<c>::template dot<R,X,K>(A[0],x); + } + }; + + template<class K, int n, int m, class X, class Y> + inline void fm_mmv (const FieldMatrix<K,n,m>& A, const X& x, Y& y) + { + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + y[i] -= A[i][j]*x[j]; + } + + template<class K> + inline void fm_mmv (const FieldMatrix<K,1,1>& A, const FieldVector<K,1>& x, FieldVector<K,1>& y) + { + y[0] -= A[0][0]*x[0]; + } + + // template meta program for usmv(x,y) + template<int I> + struct fmmeta_usmv { + template<class Mat, class K, class X, class Y, int c> + static void usmv (const Mat& A, const K& alpha, const X& x, Y& y) + { + typedef typename Mat::row_type R; + y[I] += alpha*fmmeta_dot<c>::template dot<R,X,K>(A[I],x); + fmmeta_usmv<I-1>::template usmv<Mat,K,X,Y,c>(A,alpha,x,y); + } + }; + template<> + struct fmmeta_usmv<0> { + template<class Mat, class K, class X, class Y, int c> + static void usmv (const Mat& A, const K& alpha, const X& x, Y& y) + { + typedef typename Mat::row_type R; + y[0] += alpha*fmmeta_dot<c>::template dot<R,X,K>(A[0],x); + } + }; + + // conjugate komplex does nothing for non-complex types + template<class K> + inline K fm_ck (const K& k) + { + return k; + } + + // conjugate komplex + template<class K> + inline std::complex<K> fm_ck (const std::complex<K>& c) + { + 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(ISTLPrecision<>::absolute_limit(),norm*ISTLPrecision<>::pivoting_limit()); + double singthres = std::max(ISTLPrecision<>::absolute_limit(),norm*ISTLPrecision<>::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(ISTLError,"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_ISTL_WITH_CHECKING + if (fvmeta_absreal(A[0][0])<ISTLPrecision<>::absolute_limit()) + DUNE_THROW(ISTLError,"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_ISTL_WITH_CHECKING + K detinv = A[0][0]*A[1][1]-A[0][1]*A[1][0]; + if (fvmeta_absreal(detinv)<ISTLPrecision<>::absolute_limit()) + DUNE_THROW(ISTLError,"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(ISTLPrecision<>::absolute_limit(),norm*ISTLPrecision<>::pivoting_limit()); + double singthres = std::max(ISTLPrecision<>::absolute_limit(),norm*ISTLPrecision<>::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(ISTLError,"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_ISTL_WITH_CHECKING + if (fvmeta_absreal(A[0][0])<ISTLPrecision<>::absolute_limit()) + DUNE_THROW(ISTLError,"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_ISTL_WITH_CHECKING + if (fvmeta_absreal(detinv)<ISTLPrecision<>::absolute_limit()) + DUNE_THROW(ISTLError,"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; + } + + //! left multiplication with matrix + template<class K, int n, int m> + void fm_leftmultiply (const FieldMatrix<K,n,n>& M, FieldMatrix<K,n,m>& A) + { + FieldMatrix<K,n,m> C(A); + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + { + A[i][j] = 0; + for (int k=0; k<n; k++) + A[i][j] += M[i][k]*C[k][j]; + } + } + + //! left multiplication with matrix, n=1 + template<class K> + void fm_leftmultiply (const FieldMatrix<K,1,1>& M, FieldMatrix<K,1,1>& A) + { + A[0][0] *= M[0][0]; + } + + //! left multiplication with matrix, n=2 + template<class K> + void fm_leftmultiply (const FieldMatrix<K,2,2>& M, FieldMatrix<K,2,2>& A) + { + FieldMatrix<K,2,2> C(A); + + A[0][0] = M[0][0]*C[0][0] + M[0][1]*C[1][0]; + A[0][1] = M[0][0]*C[0][1] + M[0][1]*C[1][1]; + A[1][0] = M[1][0]*C[0][0] + M[1][1]*C[1][0]; + A[1][1] = M[1][0]*C[0][1] + M[1][1]*C[1][1]; + } + + //! right multiplication with matrix + template<class K, int n, int m> + void fm_rightmultiply (const FieldMatrix<K,m,m>& M, FieldMatrix<K,n,m>& A) + { + FieldMatrix<K,n,m> C(A); + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + { + A[i][j] = 0; + for (int k=0; k<m; k++) + A[i][j] += C[i][k]*M[k][j]; + } + } + + //! right multiplication with matrix, n=1 + template<class K> + void fm_rightmultiply (const FieldMatrix<K,1,1>& M, FieldMatrix<K,1,1>& A) + { + A[0][0] *= M[0][0]; + } + + //! right multiplication with matrix, n=2 + template<class K> + void fm_rightmultiply (const FieldMatrix<K,2,2>& M, FieldMatrix<K,2,2>& A) + { + FieldMatrix<K,2,2> C(A); + + A[0][0] = C[0][0]*M[0][0] + C[0][1]*M[1][0]; + A[0][1] = C[0][0]*M[0][1] + C[0][1]*M[1][1]; + A[1][0] = C[1][0]*M[0][0] + C[1][1]*M[1][0]; + A[1][1] = C[1][0]*M[0][1] + C[1][1]*M[1][1]; + } + + + /** Matrices represent linear maps from a vector space V to a vector space W. + This class represents such a linear map by storing a two-dimensional + array of numbers of a given field type K. The number of rows and + columns is given at compile time. + + Implementation of all members uses template meta programs where appropriate + */ + template<class K, int n, int m> + class FieldMatrix + { + public: + // standard constructor and everything is sufficient ... + + //===== type definitions and constants + + //! export the type representing the field + typedef K field_type; + + //! export the type representing the components + typedef K block_type; + + //! We are at the leaf of the block recursion + enum {blocklevel = 1}; + + //! Each row is implemented by a field vector + typedef FieldVector<K,m> row_type; + + //! export size + enum {rows = n, cols = m}; + + //===== constructors + /** \brief Default constructor + */ + FieldMatrix () {} + + /** \brief Constructor initializing the whole matrix with a scalar + */ + FieldMatrix (const K& k) + { + for (int i=0; i<n; i++) p[i] = k; + } + + //===== random access interface to rows of the matrix + + //! random access to the rows + row_type& operator[] (int i) + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (i<0 || i>=n) DUNE_THROW(ISTLError,"index out of range"); +#endif + return p[i]; + } + + //! same for read only access + const row_type& operator[] (int i) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (i<0 || i>=n) DUNE_THROW(ISTLError,"index out of range"); +#endif + return p[i]; + } + + + //===== iterator interface to rows of the matrix + + // forward declaration + class ConstIterator; + + //! Iterator access to rows + class Iterator + { + public: + //! constructor + Iterator (row_type* _p, int _i) + { + p = _p; + i = _i; + } + + //! empty constructor, use with care! + Iterator () + { } + + //! prefix increment + Iterator& operator++() + { + ++i; + return *this; + } + + //! prefix decrement + Iterator& operator--() + { + --i; + return *this; + } + + //! equality + bool operator== (const Iterator& it) const + { + return (p+i)==(it.p+it.i); + } + + //! inequality + bool operator!= (const Iterator& it) const + { + return (p+i)!=(it.p+it.i); + } + + //! dereferencing + row_type& operator* () + { + return p[i]; + } + + //! arrow + row_type* operator-> () + { + return p+i; + } + + //! return index + int index () + { + return i; + } + + friend class ConstIterator; + + private: + row_type* p; + int i; + }; + + //! begin iterator + Iterator begin () + { + return Iterator(p,0); + } + + //! end iterator + Iterator end () + { + return Iterator(p,n); + } + + //! begin iterator + Iterator rbegin () + { + return Iterator(p,n-1); + } + + //! end iterator + Iterator rend () + { + return Iterator(p,-1); + } + + //! rename the iterators for easier access + typedef Iterator RowIterator; + typedef typename row_type::Iterator ColIterator; + + + //! Iterator access to rows + class ConstIterator + { + public: + //! constructor + ConstIterator (const row_type* _p, int _i) : p(_p), i(_i) + { } + + //! empty constructor, use with care! + ConstIterator () + { + p = 0; + i = 0; + } + + //! prefix increment + ConstIterator& operator++() + { + ++i; + return *this; + } + + //! prefix decrement + ConstIterator& operator--() + { + --i; + return *this; + } + + //! equality + bool operator== (const ConstIterator& it) const + { + return (p+i)==(it.p+it.i); + } + + //! inequality + bool operator!= (const ConstIterator& it) const + { + return (p+i)!=(it.p+it.i); + } + + //! equality + bool operator== (const Iterator& it) const + { + return (p+i)==(it.p+it.i); + } + + //! inequality + bool operator!= (const Iterator& it) const + { + return (p+i)!=(it.p+it.i); + } + + //! dereferencing + const row_type& operator* () const + { + return p[i]; + } + + //! arrow + const row_type* operator-> () const + { + return p+i; + } + + //! return index + int index () const + { + return i; + } + + friend class Iterator; + + private: + const row_type* p; + int i; + }; + + //! begin iterator + ConstIterator begin () const + { + return ConstIterator(p,0); + } + + //! end iterator + ConstIterator end () const + { + return ConstIterator(p,n); + } + + //! begin iterator + ConstIterator rbegin () const + { + return ConstIterator(p,n-1); + } + + //! end iterator + ConstIterator rend () const + { + return ConstIterator(p,-1); + } + + //! rename the iterators for easier access + typedef ConstIterator ConstRowIterator; + typedef typename row_type::ConstIterator ConstColIterator; + + + //===== assignment from scalar + FieldMatrix& operator= (const K& k) + { + fmmeta_assignscalar<n-1>::assignscalar(p,k); + return *this; + } + + //===== vector space arithmetic + + //! vector space addition + FieldMatrix& operator+= (const FieldMatrix& y) + { + fmmeta_plusequal<n-1>::plusequal(*this,y); + return *this; + } + + //! vector space subtraction + FieldMatrix& operator-= (const FieldMatrix& y) + { + fmmeta_minusequal<n-1>::minusequal(*this,y); + return *this; + } + + //! vector space multiplication with scalar + FieldMatrix& operator*= (const K& k) + { + fmmeta_multequal<n-1>::multequal(*this,k); + return *this; + } + + //! vector space division by scalar + FieldMatrix& operator/= (const K& k) + { + fmmeta_divequal<n-1>::divequal(*this,k); + return *this; + } + + //===== linear maps + + //! y += A x + template<class X, class Y> + void umv (const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); +#endif + fmmeta_umv<n-1>::template umv<FieldMatrix,X,Y,m-1>(*this,x,y); + } + + //! y += A^T x + template<class X, class Y> + void umtv (const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); +#endif + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + y[j] += p[i][j]*x[i]; + } + + //! y += A^H x + template<class X, class Y> + void umhv (const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); +#endif + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + y[j] += fm_ck(p[i][j])*x[i]; + } + + //! y -= A x + template<class X, class Y> + void mmv (const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); +#endif + fmmeta_mmv<n-1>::template mmv<FieldMatrix,X,Y,m-1>(*this,x,y); + //fm_mmv(*this,x,y); + } + + //! y -= A^T x + template<class X, class Y> + void mmtv (const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); +#endif + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + y[j] -= p[i][j]*x[i]; + } + + //! y -= A^H x + template<class X, class Y> + void mmhv (const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); +#endif + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + y[j] -= fm_ck(p[i][j])*x[i]; + } + + //! y += alpha A x + template<class X, class Y> + void usmv (const K& alpha, const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); +#endif + fmmeta_usmv<n-1>::template usmv<FieldMatrix,K,X,Y,m-1>(*this,alpha,x,y); + } + + //! y += alpha A^T x + template<class X, class Y> + void usmtv (const K& alpha, const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); +#endif + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + y[j] += alpha*p[i][j]*x[i]; + } + + //! y += alpha A^H x + template<class X, class Y> + void usmhv (const K& alpha, const X& x, Y& y) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (x.N()!=N()) DUNE_THROW(ISTLError,"index out of range"); + if (y.N()!=M()) DUNE_THROW(ISTLError,"index out of range"); +#endif + + for (int i=0; i<n; i++) + for (int j=0; j<m; j++) + y[j] += alpha*fm_ck(p[i][j])*x[i]; + } + + //===== norms + + //! frobenius norm: sqrt(sum over squared values of entries) + double frobenius_norm () const + { + double sum=0; + for (int i=0; i<n; ++i) sum += p[i].two_norm2(); + return sqrt(sum); + } + + //! square of frobenius norm, need for block recursion + double frobenius_norm2 () const + { + double sum=0; + for (int i=0; i<n; ++i) sum += p[i].two_norm2(); + return sum; + } + + //! infinity norm (row sum norm, how to generalize for blocks?) + double infinity_norm () const + { + double max=0; + for (int i=0; i<n; ++i) max = std::max(max,p[i].one_norm()); + return max; + } + + //! simplified infinity norm (uses Manhattan norm for complex values) + double infinity_norm_real () const + { + double max=0; + for (int i=0; i<n; ++i) max = std::max(max,p[i].one_norm_real()); + return max; + } + + //===== solve + + /** \brief Solve system A x = b + * + * \exception ISTLError if the matrix is singular + */ + template<class V> + void solve (V& x, const V& b) const + { + fm_solve(*this,x,b); + } + + /** \brief Compute inverse + * + * \exception ISTLError if the matrix is singular + */ + void invert () + { + fm_invert(*this); + } + + //! calculates the determinant of this matrix + K determinant () const; + + //! Multiplies M from the left to this matrix + FieldMatrix& leftmultiply (const FieldMatrix<K,n,n>& M) + { + fm_leftmultiply(M,*this); + return *this; + } + + //! Multiplies M from the right to this matrix + FieldMatrix& rightmultiply (const FieldMatrix<K,n,n>& M) + { + fm_rightmultiply(M,*this); + return *this; + } + + + //===== sizes + + //! number of blocks in row direction + int N () const + { + return n; + } + + //! number of blocks in column direction + int M () const + { + return m; + } + + //! row dimension of block r + int rowdim (int r) const + { + return 1; + } + + //! col dimension of block c + int coldim (int c) const + { + return 1; + } + + //! dimension of the destination vector space + int rowdim () const + { + return n; + } + + //! dimension of the source vector space + int coldim () const + { + return m; + } + + //===== query + + //! return true when (i,j) is in pattern + bool exists (int i, int j) const + { +#ifdef DUNE_ISTL_WITH_CHECKING + if (i<0 || i>=n) DUNE_THROW(ISTLError,"index out of range"); + if (j<0 || i>=m) DUNE_THROW(ISTLError,"index out of range"); +#endif + return true; + } + + //===== conversion operator + + /** \brief Sends the matrix to an output stream */ + void print (std::ostream& s) const + { + for (int i=0; i<n; i++) + s << p[i] << std::endl; + } + + /** \brief Sends the matrix to an output stream */ + friend std::ostream& operator<< (std::ostream& s, const FieldMatrix<K,n,m>& a) + { + a.print(s); + return s; + } + + private: + // the data, very simply a built in array with rowwise ordering + row_type p[n]; + }; + + + namespace HelpMat { + + // 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(ISTLError, "There is no determinant for a " << row << "x" << col << " matrix!"); + + DUNE_THROW(ISTLError, "No implementation of determinantMatrix " + << "for FieldMatrix<" << row << "," << col << "> !"); + + return 0.0; + } + + template <typename K> + static inline K determinantMatrix (const FieldMatrix<K,1,1> &matrix) + { + return matrix[0][0]; + } + + 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]; + + 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 + { + return HelpMat::determinantMatrix(*this); + } + + + /** \brief Special type for 1x1 matrices + */ + template<class K> + class K11Matrix + { + public: + // standard constructor and everything is sufficient ... + + //===== type definitions and constants + + //! export the type representing the field + typedef K field_type; + + //! export the type representing the components + typedef K block_type; + + //! We are at the leaf of the block recursion + enum {blocklevel = 1}; + + //! export size + enum {rows = 1, cols = 1}; + + //===== assignment from scalar + + K11Matrix& operator= (const K& k) + { + a = k; + return *this; + } + + //===== vector space arithmetic + + //! vector space addition + K11Matrix& operator+= (const K& y) + { + a += y; + return *this; + } + + //! vector space subtraction + K11Matrix& operator-= (const K& y) + { + a -= y; + return *this; + } + + //! vector space multiplication with scalar + K11Matrix& operator*= (const K& k) + { + a *= k; + return *this; + } + + //! vector space division by scalar + K11Matrix& operator/= (const K& k) + { + a /= k; + return *this; + } + + //===== linear maps + + //! y += A x + void umv (const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p += a * x.p; + } + + //! y += A^T x + void umtv (const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p += a * x.p; + } + + //! y += A^H x + void umhv (const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p += fm_ck(a) * x.p; + } + + //! y -= A x + void mmv (const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p -= a * x.p; + } + + //! y -= A^T x + void mmtv (const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p -= a * x.p; + } + + //! y -= A^H x + void mmhv (const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p -= fm_ck(a) * x.p; + } + + //! y += alpha A x + void usmv (const K& alpha, const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p += alpha * a * x.p; + } + + //! y += alpha A^T x + void usmtv (const K& alpha, const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p += alpha * a * x.p; + } + + //! y += alpha A^H x + void usmhv (const K& alpha, const K1Vector<K>& x, K1Vector<K>& y) const + { + y.p += alpha * fm_ck(a) * x.p; + } + + //===== norms + + //! frobenius norm: sqrt(sum over squared values of entries) + double frobenius_norm () const + { + return sqrt(fvmeta_abs2(a)); + } + + //! square of frobenius norm, need for block recursion + double frobenius_norm2 () const + { + return fvmeta_abs2(a); + } + + //! infinity norm (row sum norm, how to generalize for blocks?) + double infinity_norm () const + { + return fvmeta_abs(a); + } + + //! simplified infinity norm (uses Manhattan norm for complex values) + double infinity_norm_real () const + { + return fvmeta_abs_real(a); + } + + //===== solve + + //! Solve system A x = b + void solve (K1Vector<K>& x, const K1Vector<K>& b) const + { + x.p = b.p/a; + } + + //! compute inverse + void invert () + { + a = 1/a; + } + + //! left multiplication + K11Matrix& leftmultiply (const K11Matrix<K>& M) + { + a *= M.a; + return *this; + } + + //! left multiplication + K11Matrix& rightmultiply (const K11Matrix<K>& M) + { + a *= M.a; + return *this; + } + + + //===== sizes + + //! number of blocks in row direction + int N () const + { + return 1; + } + + //! number of blocks in column direction + int M () const + { + return 1; + } + + //! row dimension of block r + int rowdim (int r) const + { + return 1; + } + + //! col dimension of block c + int coldim (int c) const + { + return 1; + } + + //! dimension of the destination vector space + int rowdim () const + { + return 1; + } + + //! dimension of the source vector space + int coldim () const + { + return 1; + } + + //===== query + + //! return true when (i,j) is in pattern + bool exists (int i, int j) const + { + return i==0 && j==0; + } + + //===== conversion operator + + operator K () const {return a;} + + private: + // the data, just a single scalar + K a; + }; + + /** @} end documentation */ + +} // end namespace + +#endif -- GitLab