Forked from
Core Modules / dune-common
4182 commits behind, 79 commits ahead of the upstream repository.
-
Markus Blatt authored
(cherry picked from commit 3bef4991) Signed-off-by:
Carsten Gräser <graeser@dune-project.org>
Markus Blatt authored(cherry picked from commit 3bef4991) Signed-off-by:
Carsten Gräser <graeser@dune-project.org>
fmatrix.hh 14.98 KiB
// -*- 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 <cmath>
#include <cstddef>
#include <iostream>
#include <algorithm>
#include <initializer_list>
#include <dune/common/exceptions.hh>
#include <dune/common/fvector.hh>
#include <dune/common/densematrix.hh>
#include <dune/common/precision.hh>
#include <dune/common/std/constexpr.hh>
namespace Dune
{
/**
@addtogroup DenseMatVec
@{
*/
/*! \file
\brief Implements a matrix constructed from a given type
representing a field and compile-time given number of rows and columns.
*/
template< class K, int ROWS, int COLS > class FieldMatrix;
template< class K, int ROWS, int COLS >
struct DenseMatVecTraits< FieldMatrix<K,ROWS,COLS> >
{
typedef FieldMatrix<K,ROWS,COLS> derived_type;
// each row is implemented by a field vector
typedef FieldVector<K,COLS> row_type;
typedef row_type &row_reference;
typedef const row_type &const_row_reference;
typedef Dune::array<row_type,ROWS> container_type;
typedef K value_type;
typedef typename container_type::size_type size_type;
};
template< class K, int ROWS, int COLS >
struct FieldTraits< FieldMatrix<K,ROWS,COLS> >
{
typedef typename FieldTraits<K>::field_type field_type;
typedef typename FieldTraits<K>::real_type real_type;
};
/**
@brief A dense n x m matrix.
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.
*/
template<class K, int ROWS, int COLS>
class FieldMatrix : public DenseMatrix< FieldMatrix<K,ROWS,COLS> >
{
Dune::array< FieldVector<K,COLS>, ROWS > _data;
typedef DenseMatrix< FieldMatrix<K,ROWS,COLS> > Base;
public:
//! export size
enum {
//! The number of rows.
rows = ROWS,
//! The number of columns.
cols = COLS
};
typedef typename Base::size_type size_type;
typedef typename Base::row_type row_type;
typedef typename Base::row_reference row_reference;
typedef typename Base::const_row_reference const_row_reference;
//===== constructors
/** \brief Default constructor
*/
FieldMatrix () {}
/** \brief Constructor initializing the whole matrix with a scalar
*/
template< class Other >
FieldMatrix ( const Other &other )
{
DenseMatrixAssigner< FieldMatrix< K, ROWS, COLS >, Other >::apply( *this, other );
}
/** \brief Constructor initializing the matrix from a list of lists of scalars
*/
FieldMatrix (std::initializer_list<std::initializer_list<K> > const &ll)
{
assert(ll.size() == rows); // Actually, this is not needed any more!
std::copy_n(ll.begin(), std::min(static_cast<std::size_t>(ROWS),
ll.size()),
_data.begin());
}
/** \brief Constructor initializing the matrix from a list of vector
*/
FieldMatrix(std::initializer_list<Dune::FieldVector<K, cols> > const &l) {
assert(l.size() == rows); // Actually, this is not needed any more!
std::copy_n(l.begin(), std::min(static_cast<std::size_t>(ROWS),
l.size()),
_data.begin());
}
//===== assignment
using Base::operator=;
//! Multiplies M from the left to this matrix, this matrix is not modified
template<int l>
FieldMatrix<K,l,cols> leftmultiplyany (const FieldMatrix<K,l,rows>& M) const
{
FieldMatrix<K,l,cols> C;
for (size_type i=0; i<l; i++) {
for (size_type j=0; j<cols; j++) {
C[i][j] = 0;
for (size_type k=0; k<rows; k++)
C[i][j] += M[i][k]*(*this)[k][j];
}
}
return C;
}
//! Multiplies M from the right to this matrix
FieldMatrix& rightmultiply (const FieldMatrix<K,cols,cols>& M)
{
FieldMatrix<K,rows,cols> C(*this);
for (size_type i=0; i<rows; i++)
for (size_type j=0; j<cols; j++) {
(*this)[i][j] = 0;
for (size_type k=0; k<cols; k++)
(*this)[i][j] += C[i][k]*M[k][j];
}
return *this;
}
//! Multiplies M from the right to this matrix, this matrix is not modified
template<int l>
FieldMatrix<K,rows,l> rightmultiplyany (const FieldMatrix<K,cols,l>& M) const
{
FieldMatrix<K,rows,l> C;
for (size_type i=0; i<rows; i++) {
for (size_type j=0; j<l; j++) {
C[i][j] = 0;
for (size_type k=0; k<cols; k++)
C[i][j] += (*this)[i][k]*M[k][j];
}
}
return C;
}
// make this thing a matrix
DUNE_CONSTEXPR size_type mat_rows() const { return ROWS; }
DUNE_CONSTEXPR size_type mat_cols() const { return COLS; }
row_reference mat_access ( size_type i )
{
assert(i < ROWS);
return _data[i];
}
const_row_reference mat_access ( size_type i ) const
{
assert(i < ROWS);
return _data[i];
}
};
#ifndef DOXYGEN // hide specialization
/** \brief Special type for 1x1 matrices
*/
template<class K>
class FieldMatrix<K,1,1> : public DenseMatrix< FieldMatrix<K,1,1> >
{
FieldVector<K,1> _data;
typedef DenseMatrix< FieldMatrix<K,1,1> > Base;
public:
// standard constructor and everything is sufficient ...
//===== type definitions and constants
//! The type used for index access and size operations
typedef typename Base::size_type size_type;
//! We are at the leaf of the block recursion
enum {
//! The number of block levels we contain.
//! This is always one for this type.
blocklevel = 1
};
typedef typename Base::row_type row_type;
typedef typename Base::row_reference row_reference;
typedef typename Base::const_row_reference const_row_reference;
//! export size
enum {
//! \brief The number of rows.
//! This is always one for this type.
rows = 1,
//! \brief The number of columns.
//! This is always one for this type.
cols = 1
};
//===== constructors
/** \brief Default constructor
*/
FieldMatrix () {}
/** \brief Constructor initializing the whole matrix with a scalar
*/
FieldMatrix (const K& k)
{
_data[0] = k;
}
template< class Other >
FieldMatrix ( const Other &other )
{
DenseMatrixAssigner< FieldMatrix< K, 1, 1 >, Other >::apply( *this, other );
}
//===== solve
//! Multiplies M from the left to this matrix, this matrix is not modified
template<int l>
FieldMatrix<K,l,1> leftmultiplyany (const FieldMatrix<K,l,1>& M) const
{
FieldMatrix<K,l,1> C;
for (size_type j=0; j<l; j++)
C[j][0] = M[j][0]*(*this)[0][0];
return C;
}
//! left multiplication
FieldMatrix& rightmultiply (const FieldMatrix& M)
{
_data[0] *= M[0][0];
return *this;
}
//! Multiplies M from the right to this matrix, this matrix is not modified
template<int l>
FieldMatrix<K,1,l> rightmultiplyany (const FieldMatrix<K,1,l>& M) const
{
FieldMatrix<K,1,l> C;
for (size_type j=0; j<l; j++)
C[0][j] = M[0][j]*_data[0];
return C;
}
// make this thing a matrix
DUNE_CONSTEXPR size_type mat_rows() const { return 1; }
DUNE_CONSTEXPR size_type mat_cols() const { return 1; }
row_reference mat_access ( size_type i )
{
DUNE_UNUSED_PARAMETER(i);
assert(i == 0);
return _data;
}
const_row_reference mat_access ( size_type i ) const
{
DUNE_UNUSED_PARAMETER(i);
assert(i == 0);
return _data;
}
//! add scalar
FieldMatrix& operator+= (const K& k)
{
_data[0] += k;
return (*this);
}
//! subtract scalar
FieldMatrix& operator-= (const K& k)
{
_data[0] -= k;
return (*this);
}
//! multiplication with scalar
FieldMatrix& operator*= (const K& k)
{
_data[0] *= k;
return (*this);
}
//! division by scalar
FieldMatrix& operator/= (const K& k)
{
_data[0] /= k;
return (*this);
}
//===== conversion operator
operator const K& () const { return _data[0]; }
};
/** \brief Sends the matrix to an output stream */
template<typename K>
std::ostream& operator<< (std::ostream& s, const FieldMatrix<K,1,1>& a)
{
s << a[0][0];
return s;
}
#endif // DOXYGEN
namespace FMatrixHelp {
//! invert scalar without changing the original matrix
template <typename K>
static inline K invertMatrix (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
{
inverse[0][0] = 1.0/matrix[0][0];
return matrix[0][0];
}
//! invert scalar without changing the original matrix
template <typename K>
static inline K invertMatrix_retTransposed (const FieldMatrix<K,1,1> &matrix, FieldMatrix<K,1,1> &inverse)
{
return invertMatrix(matrix,inverse);
}
//! invert 2x2 Matrix without changing the original matrix
template <typename K>
static inline K invertMatrix (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
{
// code generated by maple
K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
K det_1 = 1.0/det;
inverse[0][0] = matrix[1][1] * det_1;
inverse[0][1] = - matrix[0][1] * det_1;
inverse[1][0] = - matrix[1][0] * det_1;
inverse[1][1] = matrix[0][0] * det_1;
return det;
}
//! invert 2x2 Matrix without changing the original matrix
//! return transposed matrix
template <typename K>
static inline K invertMatrix_retTransposed (const FieldMatrix<K,2,2> &matrix, FieldMatrix<K,2,2> &inverse)
{
// code generated by maple
K det = (matrix[0][0]*matrix[1][1] - matrix[0][1]*matrix[1][0]);
K det_1 = 1.0/det;
inverse[0][0] = matrix[1][1] * det_1;
inverse[1][0] = - matrix[0][1] * det_1;
inverse[0][1] = - matrix[1][0] * det_1;
inverse[1][1] = matrix[0][0] * det_1;
return det;
}
//! invert 3x3 Matrix without changing the original matrix
template <typename K>
static inline K invertMatrix (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
{
// 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]);
K t17 = 1.0/det;
inverse[0][0] = (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
inverse[0][1] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
inverse[0][2] = (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
inverse[1][0] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
inverse[1][1] = (matrix[0][0] * matrix[2][2] - t14) * t17;
inverse[1][2] = -(t6-t10) * t17;
inverse[2][0] = (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
inverse[2][1] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
inverse[2][2] = (t4-t8) * t17;
return det;
}
//! invert 3x3 Matrix without changing the original matrix
template <typename K>
static inline K invertMatrix_retTransposed (const FieldMatrix<K,3,3> &matrix, FieldMatrix<K,3,3> &inverse)
{
// 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]);
K t17 = 1.0/det;
inverse[0][0] = (matrix[1][1] * matrix[2][2] - matrix[1][2] * matrix[2][1])*t17;
inverse[1][0] = -(matrix[0][1] * matrix[2][2] - matrix[0][2] * matrix[2][1])*t17;
inverse[2][0] = (matrix[0][1] * matrix[1][2] - matrix[0][2] * matrix[1][1])*t17;
inverse[0][1] = -(matrix[1][0] * matrix[2][2] - matrix[1][2] * matrix[2][0])*t17;
inverse[1][1] = (matrix[0][0] * matrix[2][2] - t14) * t17;
inverse[2][1] = -(t6-t10) * t17;
inverse[0][2] = (matrix[1][0] * matrix[2][1] - matrix[1][1] * matrix[2][0]) * t17;
inverse[1][2] = -(matrix[0][0] * matrix[2][1] - t12) * t17;
inverse[2][2] = (t4-t8) * t17;
return det;
}
//! calculates ret = A * B
template< class K, int m, int n, int p >
static inline void multMatrix ( const FieldMatrix< K, m, n > &A,
const FieldMatrix< K, n, p > &B,
FieldMatrix< K, m, p > &ret )
{
typedef typename FieldMatrix< K, m, p > :: size_type size_type;
for( size_type i = 0; i < m; ++i )
{
for( size_type j = 0; j < p; ++j )
{
ret[ i ][ j ] = K( 0 );
for( size_type k = 0; k < n; ++k )
ret[ i ][ j ] += A[ i ][ k ] * B[ k ][ j ];
}
}
}
//! calculates ret= A_t*A
template <typename K, int rows, int cols>
static inline void multTransposedMatrix(const FieldMatrix<K,rows,cols> &matrix, FieldMatrix<K,cols,cols>& ret)
{
typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
for(size_type i=0; i<cols; i++)
for(size_type j=0; j<cols; j++)
{
ret[i][j]=0.0;
for(size_type k=0; k<rows; k++)
ret[i][j]+=matrix[k][i]*matrix[k][j];
}
}
using Dune::DenseMatrixHelp::multAssign;
//! calculates ret = matrix^T * x
template <typename K, int rows, int cols>
static inline void multAssignTransposed( const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x, FieldVector<K,cols> & ret)
{
typedef typename FieldMatrix<K,rows,cols>::size_type size_type;
for(size_type i=0; i<cols; ++i)
{
ret[i] = 0.0;
for(size_type j=0; j<rows; ++j)
ret[i] += matrix[j][i]*x[j];
}
}
//! calculates ret = matrix * x
template <typename K, int rows, int cols>
static inline FieldVector<K,rows> mult(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,cols> & x)
{
FieldVector<K,rows> ret;
multAssign(matrix,x,ret);
return ret;
}
//! calculates ret = matrix^T * x
template <typename K, int rows, int cols>
static inline FieldVector<K,cols> multTransposed(const FieldMatrix<K,rows,cols> &matrix, const FieldVector<K,rows> & x)
{
FieldVector<K,cols> ret;
multAssignTransposed( matrix, x, ret );
return ret;
}
} // end namespace FMatrixHelp
/** @} end documentation */
} // end namespace
#include "fmatrixev.hh"
#endif