DenseMatrix< T > Class Template Reference

#include <dense_matrix.h>

Inheritance diagram for DenseMatrix< T >:

List of all members.

Public Member Functions

 DenseMatrix (const unsigned int m=0, const unsigned int n=0)
virtual ~DenseMatrix ()
virtual void zero ()
operator() (const unsigned int i, const unsigned int j) const
T & operator() (const unsigned int i, const unsigned int j)
virtual T el (const unsigned int i, const unsigned int j) const
virtual T & el (const unsigned int i, const unsigned int j)
virtual void left_multiply (const DenseMatrixBase< T > &M2)
virtual void right_multiply (const DenseMatrixBase< T > &M3)
void vector_mult (DenseVector< T > &dest, const DenseVector< T > &arg) const
void vector_mult_add (DenseVector< T > &dest, const T factor, const DenseVector< T > &arg) const
void get_principal_submatrix (unsigned int sub_m, unsigned int sub_n, DenseMatrix< T > &dest) const
void get_principal_submatrix (unsigned int sub_m, DenseMatrix< T > &dest) const
DenseMatrix< T > & operator= (const DenseMatrix< T > &other_matrix)
void swap (DenseMatrix< T > &other_matrix)
void resize (const unsigned int m, const unsigned int n)
void scale (const T factor)
DenseMatrix< T > & operator*= (const T factor)
void add (const T factor, const DenseMatrix< T > &mat)
bool operator== (const DenseMatrix< T > &mat) const
bool operator!= (const DenseMatrix< T > &mat) const
DenseMatrix< T > & operator+= (const DenseMatrix< T > &mat)
DenseMatrix< T > & operator-= (const DenseMatrix< T > &mat)
Real min () const
Real max () const
Real l1_norm () const
Real linfty_norm () const
void left_multiply_transpose (const DenseMatrix< T > &A)
void right_multiply_transpose (const DenseMatrix< T > &A)
transpose (const unsigned int i, const unsigned int j) const
void get_transpose (DenseMatrix< T > &dest) const
std::vector< T > & get_values ()
const std::vector< T > & get_values () const
void condense (const unsigned int i, const unsigned int j, const T val, DenseVector< T > &rhs)
void lu_solve (DenseVector< T > &b, DenseVector< T > &x, const bool partial_pivot=false)
template<typename T2 >
void cholesky_solve (DenseVector< T2 > &b, DenseVector< T2 > &x)
det ()
unsigned int m () const
unsigned int n () const
void print (std::ostream &os) const
void print_scientific (std::ostream &os) const
template<typename T2 , typename T3 >
boostcopy::enable_if_c
< ScalarTraits< T2 >::value,
void >::type 
add (const T2 factor, const DenseMatrixBase< T3 > &mat)

Public Attributes

bool use_blas_lapack

Protected Member Functions

void multiply (DenseMatrixBase< T > &M1, const DenseMatrixBase< T > &M2, const DenseMatrixBase< T > &M3)
void condense (const unsigned int i, const unsigned int j, const T val, DenseVectorBase< T > &rhs)

Protected Attributes

unsigned int _m
unsigned int _n

Private Types

enum  DecompositionType { LU = 0, CHOLESKY = 1, LU_BLAS_LAPACK, NONE }
enum  _BLAS_Multiply_Flag { LEFT_MULTIPLY = 0, RIGHT_MULTIPLY, LEFT_MULTIPLY_TRANSPOSE, RIGHT_MULTIPLY_TRANSPOSE }

Private Member Functions

void _lu_decompose (const bool partial_pivot=false)
void _lu_back_substitute (DenseVector< T > &b, DenseVector< T > &x, const bool partial_pivot=false) const
void _cholesky_decompose ()
template<typename T2 >
void _cholesky_back_substitute (DenseVector< T2 > &b, DenseVector< T2 > &x) const
void _multiply_blas (const DenseMatrixBase< T > &other, _BLAS_Multiply_Flag flag)
void _lu_decompose_lapack ()
void _lu_back_substitute_lapack (DenseVector< T > &b, DenseVector< T > &x)
void _matvec_blas (T alpha, T beta, DenseVector< T > &dest, const DenseVector< T > &arg) const

Private Attributes

std::vector< T > _val
DecompositionType _decomposition_type
std::vector< int > _pivots

Friends

std::ostream & operator<< (std::ostream &os, const DenseMatrixBase< T > &m)


Detailed Description

template<typename T>
class DenseMatrix< T >

Defines a dense matrix for use in Finite Element-type computations. Useful for storing element stiffness matrices before summation into a global matrix.

Author:
Benjamin S. Kirk, 2002

Definition at line 49 of file dense_matrix.h.


Member Enumeration Documentation

template<typename T >
enum DenseMatrix::_BLAS_Multiply_Flag [private]

Enumeration used to determine the behavior of the _multiply_blas function.

Enumerator:
LEFT_MULTIPLY 
RIGHT_MULTIPLY 
LEFT_MULTIPLY_TRANSPOSE 
RIGHT_MULTIPLY_TRANSPOSE 

Definition at line 378 of file dense_matrix.h.

00378                            {
00379     LEFT_MULTIPLY = 0,
00380     RIGHT_MULTIPLY,
00381     LEFT_MULTIPLY_TRANSPOSE,
00382     RIGHT_MULTIPLY_TRANSPOSE
00383   };

template<typename T >
enum DenseMatrix::DecompositionType [private]

The decomposition schemes above change the entries of the matrix A. It is therefore an error to call A.lu_solve() and subsequently call A.cholesky_solve() since the result will probably not match any desired outcome. This typedef keeps track of which decomposition has been called for this matrix.

Enumerator:
LU 
CHOLESKY 
LU_BLAS_LAPACK 
NONE 

Definition at line 366 of file dense_matrix.h.

00366 {LU=0, CHOLESKY=1, LU_BLAS_LAPACK, NONE};


Constructor & Destructor Documentation

template<typename T >
DenseMatrix< T >::DenseMatrix ( const unsigned int  m = 0,
const unsigned int  n = 0 
) [inline]

Constructor. Creates a dense matrix of dimension m by n.

Definition at line 482 of file dense_matrix.h.

References DenseMatrix< T >::resize().

00484   : DenseMatrixBase<T>(m,n),
00485 #if defined(LIBMESH_HAVE_PETSC) && defined(LIBMESH_USE_REAL_NUMBERS)
00486     use_blas_lapack(true),
00487 #else
00488     use_blas_lapack(false),
00489 #endif
00490     _decomposition_type(NONE)
00491 {
00492   this->resize(m,n);
00493 }

template<typename T >
virtual DenseMatrix< T >::~DenseMatrix (  )  [inline, virtual]

Copy-constructor. Destructor. Empty.

Definition at line 67 of file dense_matrix.h.

00067 {}


Member Function Documentation

template<typename T >
template<typename T2 >
void DenseMatrix< T >::_cholesky_back_substitute ( DenseVector< T2 > &  b,
DenseVector< T2 > &  x 
) const [inline, private]

Solves the equation Ax=b for the unknown value x and rhs b based on the Cholesky factorization of A. Note that this method may be used when A is real-valued and b and x are complex-valued.

Definition at line 617 of file dense_matrix.C.

References DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), and DenseVector< T >::resize().

Referenced by DenseMatrix< T >::cholesky_solve().

00619 {
00620   // Shorthand notation for number of rows and columns.
00621   const unsigned int
00622     m = this->m(),
00623     n = this->n();
00624 
00625   // Just to be really sure...
00626   libmesh_assert(m==n);
00627 
00628   // A convenient reference to *this
00629   const DenseMatrix<T>& A = *this;
00630    
00631   // Now compute the solution to Ax =b using the factorization.
00632   x.resize(m);
00633   
00634   // Solve for Ly=b
00635   for (unsigned int i=0; i<n; ++i)
00636     {
00637       for (unsigned int k=0; k<i; ++k)
00638         b(i) -= A(i,k)*x(k);
00639       
00640       x(i) = b(i) / A(i,i);
00641     }
00642   
00643   // Solve for L^T x = y
00644   for (unsigned int i=0; i<n; ++i)
00645     {
00646       const unsigned int ib = (n-1)-i;
00647 
00648       for (unsigned int k=(ib+1); k<n; ++k)
00649         x(ib) -= A(k,ib) * x(k);
00650       
00651       x(ib) /= A(ib,ib);
00652     }
00653 }

template<typename T >
void DenseMatrix< T >::_cholesky_decompose (  )  [inline, private]

Decomposes a symmetric positive definite matrix into a product of two lower triangular matrices according to A = LL^T. Note that this program generates an error if the matrix is not SPD.

Definition at line 566 of file dense_matrix.C.

References DenseMatrix< T >::_decomposition_type, DenseMatrix< T >::CHOLESKY, DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), and DenseMatrix< T >::NONE.

Referenced by DenseMatrix< T >::cholesky_solve().

00567 {
00568   // If we called this function, there better not be any
00569   // previous decomposition of the matrix.
00570   libmesh_assert(this->_decomposition_type == NONE);
00571   
00572   // Shorthand notation for number of rows and columns.
00573   const unsigned int
00574     m = this->m(),
00575     n = this->n();
00576 
00577   // Just to be really sure...
00578   libmesh_assert(m==n);
00579 
00580   // A convenient reference to *this
00581   DenseMatrix<T>& A = *this;
00582   
00583   for (unsigned int i=0; i<m; ++i)
00584     {
00585       for (unsigned int j=i; j<n; ++j)
00586         {
00587           for (unsigned int k=0; k<i; ++k)
00588             A(i,j) -= A(i,k) * A(j,k);
00589 
00590           if (i == j)
00591             {
00592 #ifndef LIBMESH_USE_COMPLEX_NUMBERS
00593               if (A(i,j) <= 0.0)
00594                 {
00595                   std::cerr << "Error! Can only use Cholesky decomposition "
00596                             << "with symmetric positive definite matrices."
00597                             << std::endl;
00598                   libmesh_error();
00599                 }
00600 #endif
00601 
00602               A(i,i) = std::sqrt(A(i,j));
00603             }
00604           else
00605             A(j,i) = A(i,j) / A(i,i);
00606         }
00607     }
00608   
00609   // Set the flag for CHOLESKY decomposition
00610   this->_decomposition_type = CHOLESKY;
00611 }

template<typename T >
void DenseMatrix< T >::_lu_back_substitute ( DenseVector< T > &  b,
DenseVector< T > &  x,
const bool  partial_pivot = false 
) const [inline, private]

Solves the system Ax=b through back substitution. This function is private since it is only called as part of the implementation of the lu_solve(...) function.

Definition at line 368 of file dense_matrix.C.

References DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), DenseVector< T >::resize(), DenseVector< T >::size(), and libMesh::zero.

Referenced by DenseMatrix< T >::lu_solve().

00371 {
00372   const unsigned int
00373     n = this->n();
00374 
00375   libmesh_assert (this->m() == n);
00376   libmesh_assert (this->m() == b.size());
00377   
00378   x.resize (n);
00379 
00380   // A convenient reference to *this
00381   const DenseMatrix<T>& A = *this;
00382 
00383   // Transform the RHS vector
00384   for (unsigned int i=0; i<(n-1); i++)
00385     {
00386       // Get the diagonal entry and take its inverse
00387       const T diag = A(i,i);
00388       
00389       libmesh_assert (diag != libMesh::zero);
00390   
00391       const T diag_inv = 1./diag;
00392 
00393       // Get the entry b(i) and store it
00394       const T bi = b(i);
00395       
00396       for (unsigned int j=(i+1); j<n; j++)
00397         b(j) -= bi*A(j,i)*diag_inv;
00398     }
00399 
00400 
00401   // Perform back-substitution
00402   {
00403     x(n-1) = b(n-1)/A(n-1,n-1);
00404 
00405     for (unsigned int i=0; i<=(n-1); i++)
00406       {
00407         const unsigned int ib = (n-1)-i;
00408 
00409         // Get the diagonal and take its inverse
00410         const T diag = A(ib,ib);
00411 
00412         libmesh_assert (diag != libMesh::zero);
00413 
00414         const T diag_inv = 1./diag;
00415         
00416         for (unsigned int j=(ib+1); j<n; j++)
00417           {
00418             b(ib) -= A(ib,j)*x(j);
00419             x(ib)  = b(ib)*diag_inv;
00420           }
00421       }
00422   }
00423 }

template<typename T >
void DenseMatrix< T >::_lu_back_substitute_lapack ( DenseVector< T > &  b,
DenseVector< T > &  x 
) [inline, private]

Companion function to _lu_decompose_lapack(). Do not use directly, called through the public lu_solve() interface. This function is logically const in that it does not modify the matrix, but since we are just calling LAPACK routines, it's less const_cast hassle to just declare the function non-const. [ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 297 of file dense_matrix_blas_lapack.C.

References DenseMatrix< T >::_pivots, DenseMatrix< T >::_val, DenseVector< T >::get_values(), DenseMatrixBase< T >::m(), and DenseVector< T >::swap().

Referenced by DenseMatrix< T >::lu_solve().

00299 {
00300   // The calling sequence for getrs is:
00301   // dgetrs(TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO)
00302 
00303   //    trans   (input) char*
00304   //            'n' for no tranpose, 't' for transpose
00305   char TRANS[] = "t";
00306   
00307   //    N       (input) int*
00308   //            The order of the matrix A.  N >= 0.
00309   int N = this->m();
00310   
00311  
00312   //    NRHS    (input) int*
00313   //            The number of right hand sides, i.e., the number of columns
00314   //            of the matrix B.  NRHS >= 0.
00315   int NRHS = 1;
00316  
00317   //    A       (input) DOUBLE PRECISION array, dimension (LDA,N)
00318   //            The factors L and U from the factorization A = P*L*U
00319   //            as computed by dgetrf.
00320   // Here, we pass &(_val[0])
00321   
00322   //    LDA     (input) int*
00323   //            The leading dimension of the array A.  LDA >= max(1,N).
00324   int LDA = N;
00325     
00326   //    ipiv    (input) int array, dimension (N)
00327   //            The pivot indices from DGETRF; for 1<=i<=N, row i of the
00328   //            matrix was interchanged with row IPIV(i).
00329   // Here, we pass &(_pivots[0]) which was computed in _lu_decompose_lapack
00330  
00331   //    B       (input/output) DOUBLE PRECISION array, dimension (LDB,NRHS)
00332   //            On entry, the right hand side matrix B.
00333   //            On exit, the solution matrix X.
00334   // Here, we pass a copy of the rhs vector's data array in x, so that the
00335   // passed right-hand side b is unmodified.  I don't see a way around this
00336   // copy if we want to maintain an unmodified rhs in LibMesh.
00337   // x = b;
00338   // std::vector<T>& x_vec = x.get_values();
00339 
00340   // We can avoid the copy if we don't care about overwriting the RHS: just
00341   // pass b to the Lapack routine and then swap with x before exiting
00342   std::vector<T>& x_vec = b.get_values();
00343  
00344   //    LDB     (input) int*
00345   //            The leading dimension of the array B.  LDB >= max(1,N).
00346   int LDB = N;
00347  
00348   //    INFO    (output) int*
00349   //            = 0:  successful exit
00350   //            < 0:  if INFO = -i, the i-th argument had an illegal value
00351   int INFO = 0;
00352   
00353   // Finally, ready to call the Lapack getrs function
00354   LAPACKgetrs_(TRANS, &N, &NRHS, &(_val[0]), &LDA, &(_pivots[0]), &(x_vec[0]), &LDB, &INFO);
00355 
00356   // Check return value for errors
00357   if (INFO != 0)
00358     {
00359       std::cout << "INFO="
00360                 << INFO
00361                 << ", Error during Lapack LU solve!" << std::endl;
00362       libmesh_error();
00363     }
00364 
00365   // Swap b and x.  The solution will then be in x, and whatever was originally
00366   // in x, maybe garbage, maybe nothing, will be in b.
00367   // FIXME: Rewrite the LU and Cholesky solves to just take one input, and overwrite
00368   // the input.  This *should* make user code simpler, as they don't have to create
00369   // an extra vector just to pass it in to the solve function!
00370   b.swap(x);
00371 }

template<typename T >
void DenseMatrix< T >::_lu_decompose ( const bool  partial_pivot = false  )  [inline, private]

Form the LU decomposition of the matrix. This function is private since it is only called as part of the implementation of the lu_solve(...) function.

Definition at line 433 of file dense_matrix.C.

References DenseMatrix< T >::_decomposition_type, DenseMatrix< T >::LU, DenseMatrixBase< T >::m(), DenseMatrix< T >::NONE, and libMesh::zero.

Referenced by DenseMatrix< T >::det(), and DenseMatrix< T >::lu_solve().

00434 {
00435   // If this function was called, there better not be any
00436   // previous decomposition of the matrix.
00437   libmesh_assert(this->_decomposition_type == NONE);
00438   
00439   // Get the matrix size and make sure it is square
00440   const unsigned int
00441     m = this->m();
00442 
00443   // A convenient reference to *this
00444   DenseMatrix<T>& A = *this;
00445   
00446   // Straight, vanilla LU factorization without pivoting
00447   if (!partial_pivot)
00448     {
00449       
00450       // For each row in the matrix
00451       for (unsigned int i=0; i<m; i++)
00452         {
00453           // Get the diagonal entry and take its inverse
00454           const T diag = A(i,i);
00455 
00456           libmesh_assert (diag != libMesh::zero);
00457 
00458           const T diag_inv = 1./diag;
00459           
00460           // For each row in the submatrix
00461           for (unsigned int j=i+1; j<m; j++)
00462             {
00463               // Get the scale factor for this row
00464               const T fact = A(j,i)*diag_inv;
00465               
00466               // For each column in the subrow scale it
00467               // by the factor
00468               for (unsigned int k=i+1; k<m; k++)
00469                 A(j,k) -= fact*A(i,k);        
00470             }
00471         }
00472     }
00473   
00474   // Do partial pivoting.
00475   else
00476     {
00477       libmesh_error();
00478     }
00479   
00480   // Set the flag for LU decomposition
00481   this->_decomposition_type = LU;
00482 }

template<typename T >
void DenseMatrix< T >::_lu_decompose_lapack (  )  [inline, private]

Computes an LU factorization of the matrix using the Lapack routine "getrf". This routine should only be used by the "use_blas_lapack" branch of the lu_solve() function. After the call to this function, the matrix is replaced by its factorized version, and the DecompositionType is set to LU_BLAS_LAPACK. [ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 219 of file dense_matrix_blas_lapack.C.

References DenseMatrix< T >::_decomposition_type, DenseMatrix< T >::_pivots, DenseMatrix< T >::_val, DenseMatrix< T >::LU_BLAS_LAPACK, DenseMatrixBase< T >::m(), std::min(), DenseMatrixBase< T >::n(), and DenseMatrix< T >::NONE.

Referenced by DenseMatrix< T >::lu_solve().

00220 {
00221   // If this function was called, there better not be any
00222   // previous decomposition of the matrix.
00223   libmesh_assert(this->_decomposition_type == NONE);
00224 
00225   // The calling sequence for dgetrf is:
00226   // dgetrf(M, N, A, lda, ipiv, info)
00227   
00228   //    M       (input) int*
00229   //            The number of rows of the matrix A.  M >= 0.
00230   // In C/C++, pass the number of *cols* of A
00231   int M = this->n();
00232     
00233   //    N       (input) int*
00234   //            The number of columns of the matrix A.  N >= 0.
00235   // In C/C++, pass the number of *rows* of A
00236   int N = this->m();
00237   
00238   //    A (input/output) double precision array, dimension (LDA,N)
00239   //      On entry, the M-by-N matrix to be factored.
00240   //      On exit, the factors L and U from the factorization
00241   //      A = P*L*U; the unit diagonal elements of L are not stored.
00242   // Here, we pass &(_val[0]).
00243   
00244   //    LDA     (input) int*
00245   //            The leading dimension of the array A.  LDA >= max(1,M).
00246   int LDA = M;
00247   
00248   //    ipiv    (output) integer array, dimension (min(m,n))
00249   //            The pivot indices; for 1 <= i <= min(m,n), row i of the
00250   //            matrix was interchanged with row IPIV(i).
00251   // Here, we pass &(_pivots[0]), a private class member used to store pivots
00252   this->_pivots.resize( std::min(M,N) );
00253   
00254   //    info    (output) int*
00255   //            = 0:  successful exit
00256   //            < 0:  if INFO = -i, the i-th argument had an illegal value
00257   //            > 0:  if INFO = i, U(i,i) is exactly zero. The factorization
00258   //                  has been completed, but the factor U is exactly
00259   //                  singular, and division by zero will occur if it is used
00260   //                  to solve a system of equations.
00261   int INFO = 0;
00262 
00263   // Ready to call the actual factorization routine through PETSc's interface
00264   LAPACKgetrf_(&M, &N, &(this->_val[0]), &LDA, &(_pivots[0]), &INFO);
00265 
00266   // Check return value for errors
00267   if (INFO != 0)
00268     {
00269       std::cout << "INFO="
00270                 << INFO
00271                 << ", Error during Lapack LU factorization!" << std::endl;
00272       libmesh_error();
00273     }
00274   
00275   // Set the flag for LU decomposition
00276   this->_decomposition_type = LU_BLAS_LAPACK;
00277 }

template<typename T >
void DenseMatrix< T >::_matvec_blas ( alpha,
beta,
DenseVector< T > &  dest,
const DenseVector< T > &  arg 
) const [inline, private]

Uses the BLAS GEMV function (through PETSc) to compute

dest := alpha*A*arg + beta*dest

where alpha and beta are scalars, A is this matrix, and arg and dest are input vectors of appropriate size.

[ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 392 of file dense_matrix_blas_lapack.C.

References DenseVector< T >::get_values(), DenseMatrix< T >::get_values(), DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), and DenseVector< T >::size().

Referenced by DenseMatrix< T >::vector_mult(), and DenseMatrix< T >::vector_mult_add().

00395 {
00396   // Ensure that dest and arg are proper size
00397   // dest  ~ A     * arg
00398   // (mx1)   (mxn) * (nx1)
00399   if ((dest.size() != this->m()) || (arg.size() != this->n()))
00400     {
00401       std::cout << "Improper input argument sizes!" << std::endl;
00402       libmesh_error();
00403     }
00404   
00405   // Calling sequence for dgemv:
00406   //
00407   // dgemv(TRANS,M,N,ALPHA,A,LDA,X,INCX,BETA,Y,INCY)
00408   
00409   //   TRANS  - CHARACTER*1, 't' for transpose, 'n' for non-transpose multiply
00410   char TRANS[] = "t";
00411   
00412   //   M      - INTEGER.
00413   //            On entry, M specifies the number of rows of the matrix A.
00414   // In C/C++, pass the number of *cols* of A
00415   int M = this->n();
00416     
00417   //   N      - INTEGER.
00418   //            On entry, N specifies the number of columns of the matrix A.
00419   // In C/C++, pass the number of *rows* of A
00420   int N = this->m();
00421   
00422   //   ALPHA  - DOUBLE PRECISION.
00423   // The scalar constant passed to this function
00424 
00425   //   A      - DOUBLE PRECISION array of DIMENSION ( LDA, n ).
00426   //            Before entry, the leading m by n part of the array A must
00427   //            contain the matrix of coefficients.
00428   // The matrix, *this.  Note that _matvec_blas is called from
00429   // a const function, vector_mult(), and so we have made this function const
00430   // as well.  Since BLAS knows nothing about const, we have to cast it away
00431   // now.
00432   DenseMatrix<T>& a_ref = const_cast< DenseMatrix<T>& > ( *this );
00433   std::vector<T>& a = a_ref.get_values();
00434 
00435   //   LDA    - INTEGER.
00436   //            On entry, LDA specifies the first dimension of A as declared
00437   //            in the calling (sub) program. LDA must be at least
00438   //            max( 1, m ).
00439   int LDA = M;
00440   
00441   //   X      - DOUBLE PRECISION array of DIMENSION at least
00442   //            ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n'
00443   //            and at least
00444   //            ( 1 + ( m - 1 )*abs( INCX ) ) otherwise.
00445   //            Before entry, the incremented array X must contain the
00446   //            vector x.
00447   // Here, we must cast away the const-ness of "arg" since BLAS knows
00448   // nothing about const
00449   DenseVector<T>& x_ref = const_cast< DenseVector<T>& > ( arg );
00450   std::vector<T>& x = x_ref.get_values();
00451   
00452   //   INCX   - INTEGER.
00453   //            On entry, INCX specifies the increment for the elements of
00454   //            X. INCX must not be zero.
00455   int INCX = 1;
00456   
00457   //   BETA   - DOUBLE PRECISION.
00458   //            On entry, BETA specifies the scalar beta. When BETA is
00459   //            supplied as zero then Y need not be set on input.
00460   // The second scalar constant passed to this function
00461 
00462   //   Y      - DOUBLE PRECISION array of DIMENSION at least
00463   //            ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n'
00464   //            and at least
00465   //            ( 1 + ( n - 1 )*abs( INCY ) ) otherwise.
00466   //            Before entry with BETA non-zero, the incremented array Y
00467   //            must contain the vector y. On exit, Y is overwritten by the
00468   //            updated vector y.
00469   // The input vector "dest"
00470   std::vector<T>& y = dest.get_values();
00471 
00472   //   INCY   - INTEGER.
00473   //            On entry, INCY specifies the increment for the elements of
00474   //            Y. INCY must not be zero.
00475   int INCY = 1;
00476   
00477   // Finally, ready to call the BLAS function
00478   BLASgemv_(TRANS, &M, &N, &alpha, &(a[0]), &LDA, &(x[0]), &INCX, &beta, &(y[0]), &INCY);
00479 }

template<typename T >
void DenseMatrix< T >::_multiply_blas ( const DenseMatrixBase< T > &  other,
_BLAS_Multiply_Flag  flag 
) [inline, private]

The _multiply_blas function computes A <- op(A) * op(B) using BLAS gemm function. Used in the right_multiply(), left_multiply(), right_multiply_transpose(), and left_multiply_tranpose() routines. [ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 39 of file dense_matrix_blas_lapack.C.

References DenseMatrixBase< T >::_m, DenseMatrixBase< T >::_n, DenseMatrix< T >::_val, DenseMatrix< T >::LEFT_MULTIPLY, DenseMatrix< T >::LEFT_MULTIPLY_TRANSPOSE, DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), DenseMatrix< T >::RIGHT_MULTIPLY, DenseMatrix< T >::RIGHT_MULTIPLY_TRANSPOSE, and DenseMatrix< T >::swap().

Referenced by DenseMatrix< T >::left_multiply(), DenseMatrix< T >::left_multiply_transpose(), DenseMatrix< T >::right_multiply(), and DenseMatrix< T >::right_multiply_transpose().

00041 {
00042   int result_size = 0;
00043   
00044   // For each case, determine the size of the final result make sure
00045   // that the inner dimensions match
00046   switch (flag)
00047     {
00048     case LEFT_MULTIPLY:
00049       {
00050         result_size = other.m() * this->n();
00051         if (other.n() == this->m())
00052           break;
00053       }
00054     case RIGHT_MULTIPLY:
00055       {
00056         result_size = other.n() * this->m();
00057         if (other.m() == this->n())
00058           break;
00059       }
00060     case LEFT_MULTIPLY_TRANSPOSE:
00061       {
00062         result_size = other.n() * this->n();
00063         if (other.m() == this->m())
00064           break;
00065       }
00066     case RIGHT_MULTIPLY_TRANSPOSE:
00067       {
00068         result_size = other.m() * this->m();
00069         if (other.n() == this->n())
00070           break;
00071       }
00072     default:
00073       {
00074         std::cout << "Unknown flag selected or matrices are ";
00075         std::cout << "incompatible for multiplication." << std::endl;
00076         libmesh_error();
00077       }
00078     }
00079 
00080   // For this to work, the passed arg. must actually be a DenseMatrix<T>
00081   const DenseMatrix<T>* const_that = dynamic_cast< const DenseMatrix<T>* >(&other);
00082   if (!const_that)
00083     {
00084       std::cerr << "Unable to cast input matrix to usable type." << std::endl;
00085       libmesh_error();
00086     }
00087 
00088   // Also, although 'that' is logically const in this BLAS routine,
00089   // the PETSc BLAS interface does not specify that any of the inputs are
00090   // const.  To use it, I must cast away const-ness.
00091   DenseMatrix<T>* that = const_cast< DenseMatrix<T>* > (const_that);
00092 
00093   // Initialize A, B pointers for LEFT_MULTIPLY* cases
00094   DenseMatrix<T>
00095     *A = this,
00096     *B = that;
00097 
00098   // For RIGHT_MULTIPLY* cases, swap the meaning of A and B.
00099   // Here is a full table of combinations we can pass to BLASgemm, and what the answer is when finished:
00100   // pass A B   -> (Fortran) -> A^T B^T -> (C++) -> (A^T B^T)^T -> (identity) -> B A   "lt multiply"
00101   // pass B A   -> (Fortran) -> B^T A^T -> (C++) -> (B^T A^T)^T -> (identity) -> A B   "rt multiply"
00102   // pass A B^T -> (Fortran) -> A^T B   -> (C++) -> (A^T B)^T   -> (identity) -> B^T A "lt multiply t"
00103   // pass B^T A -> (Fortran) -> B A^T   -> (C++) -> (B A^T)^T   -> (identity) -> A B^T "rt multiply t"
00104   if (flag==RIGHT_MULTIPLY || flag==RIGHT_MULTIPLY_TRANSPOSE)
00105     std::swap(A,B);
00106 
00107   // transa, transb values to pass to blas
00108   char
00109     transa[] = "n",
00110     transb[] = "n";
00111 
00112   // Integer values to pass to BLAS:
00113   //
00114   // M  
00115   // In Fortran, the number of rows of op(A),
00116   // In the BLAS documentation, typically known as 'M'.
00117   //
00118   // In C/C++, we set:
00119   // M = n_cols(A) if (transa='n')
00120   //     n_rows(A) if (transa='t')
00121   int M = static_cast<int>( A->n() );
00122 
00123   // N
00124   // In Fortran, the number of cols of op(B), and also the number of cols of C.
00125   // In the BLAS documentation, typically known as 'N'.
00126   //        
00127   // In C/C++, we set:
00128   // N = n_rows(B) if (transb='n')
00129   //     n_cols(B) if (transb='t')
00130   int N = static_cast<int>( B->m() );
00131 
00132   // K
00133   // In Fortran, the number of cols of op(A), and also
00134   // the number of rows of op(B). In the BLAS documentation,
00135   // typically known as 'K'.
00136   //
00137   // In C/C++, we set:
00138   // K = n_rows(A) if (transa='n')
00139   //     n_cols(A) if (transa='t')
00140   int K = static_cast<int>( A->m() );
00141 
00142   // LDA (leading dimension of A). In our cases,
00143   // LDA is always the number of columns of A.
00144   int LDA = static_cast<int>( A->n() );
00145 
00146   // LDB (leading dimension of B).  In our cases,
00147   // LDB is always the number of columns of B.
00148   int LDB = static_cast<int>( B->n() );
00149 
00150   if (flag == LEFT_MULTIPLY_TRANSPOSE)
00151     {
00152       transb[0] = 't';
00153       N = static_cast<int>( B->n() );
00154     }
00155 
00156   else if (flag == RIGHT_MULTIPLY_TRANSPOSE)
00157     {
00158       transa[0] = 't';
00159       std::swap(M,K);
00160     }
00161 
00162   // LDC (leading dimension of C).  LDC is the
00163   // number of columns in the solution matrix.
00164   int LDC = M;
00165   
00166   // Scalar values to pass to BLAS
00167   //
00168   // scalar multiplying the whole product AB 
00169   T alpha = 1.;
00170   
00171   // scalar multiplying C, which is the original matrix.
00172   T beta  = 0.;
00173 
00174   // Storage for the result
00175   std::vector<T> result (result_size);
00176 
00177   // Finally ready to call the BLAS
00178   BLASgemm_(transa, transb, &M, &N, &K, &alpha, &(A->_val[0]), &LDA, &(B->_val[0]), &LDB, &beta, &result[0], &LDC);
00179 
00180   // Update the relevant dimension for this matrix.
00181   switch (flag)
00182     {
00183     case LEFT_MULTIPLY:            { this->_m = other.m(); break; }
00184     case RIGHT_MULTIPLY:           { this->_n = other.n(); break; }
00185     case LEFT_MULTIPLY_TRANSPOSE:  { this->_m = other.n(); break; }
00186     case RIGHT_MULTIPLY_TRANSPOSE: { this->_n = other.m(); break; }
00187     default:
00188       {
00189         std::cout << "Unknown flag selected." << std::endl;
00190         libmesh_error();
00191       }
00192     }
00193   
00194   // Swap my data vector with the result
00195   this->_val.swap(result);
00196 }

template<typename T >
template<typename T2 , typename T3 >
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type DenseMatrixBase< T >::add ( const T2  factor,
const DenseMatrixBase< T3 > &  mat 
) [inline, inherited]

Adds factor to every element in the matrix. This should only work if T += T2 * T3 is valid C++ and if T2 is scalar. Return type is void

Definition at line 183 of file dense_matrix_base.h.

References DenseMatrixBase< T >::el(), DenseMatrixBase< T >::m(), and DenseMatrixBase< T >::n().

00185 {
00186   libmesh_assert (this->m() == mat.m());
00187   libmesh_assert (this->n() == mat.n());
00188 
00189   for (unsigned int j=0; j<this->n(); j++)
00190     for (unsigned int i=0; i<this->m(); i++)
00191       this->el(i,j) += factor*mat.el(i,j);
00192 }

template<typename T >
void DenseMatrix< T >::add ( const T  factor,
const DenseMatrix< T > &  mat 
) [inline]

Adds factor times mat to this matrix.

Definition at line 621 of file dense_matrix.h.

References DenseMatrix< T >::_val.

Referenced by FEMSystem::assembly().

00622 {
00623   for (unsigned int i=0; i<_val.size(); i++)
00624     _val[i] += factor * mat._val[i];
00625 }

template<typename T >
template<typename T2 >
void DenseMatrix< T >::cholesky_solve ( DenseVector< T2 > &  b,
DenseVector< T2 > &  x 
) [inline]

For symmetric positive definite (SPD) matrices. A Cholesky factorization of A such that A = L L^T is about twice as fast as a standard LU factorization. Therefore you can use this method if you know a-priori that the matrix is SPD. If the matrix is not SPD, an error is generated. One nice property of cholesky decompositions is that they do not require pivoting for stability. Note that this method may also be used when A is real-valued and x and b are complex-valued.

Definition at line 529 of file dense_matrix.C.

References DenseMatrix< T >::_cholesky_back_substitute(), DenseMatrix< T >::_cholesky_decompose(), DenseMatrix< T >::_decomposition_type, DenseMatrix< T >::CHOLESKY, and DenseMatrix< T >::NONE.

Referenced by FEBase::coarsened_dof_values(), FEBase::compute_periodic_constraints(), FEBase::compute_proj_constraints(), and System::ProjectVector::operator()().

00531 {
00532   // Check for a previous decomposition
00533   switch(this->_decomposition_type)
00534     {
00535     case NONE:
00536       {
00537         this->_cholesky_decompose ();
00538         break;
00539       }
00540 
00541     case CHOLESKY:
00542       {
00543         // Already factored, just need to call back_substitute.
00544         break;
00545       }
00546       
00547     default:
00548       {
00549         std::cerr << "Error! This matrix already has a "
00550                   << "different decomposition..."
00551                   << std::endl;
00552         libmesh_error();
00553       }
00554     }
00555 
00556   // Perform back substitution
00557   this->_cholesky_back_substitute (b, x);
00558 }

template<typename T >
void DenseMatrixBase< T >::condense ( const unsigned int  i,
const unsigned int  j,
const T  val,
DenseVectorBase< T > &  rhs 
) [inline, protected, inherited]

Condense-out the (i,j) entry of the matrix, forcing it to take on the value val. This is useful in numerical simulations for applying boundary conditions. Preserves the symmetry of the matrix.

Definition at line 57 of file dense_matrix_base.C.

References DenseMatrixBase< T >::_m, DenseMatrixBase< T >::el(), DenseVectorBase< T >::el(), DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), and DenseVectorBase< T >::size().

00061 {
00062   libmesh_assert (this->_m == rhs.size());
00063   libmesh_assert (iv == jv);
00064 
00065 
00066   // move the known value into the RHS
00067   // and zero the column
00068   for (unsigned int i=0; i<this->m(); i++)
00069     {
00070       rhs.el(i) -= this->el(i,jv)*val;
00071       this->el(i,jv) = 0.;
00072     }
00073 
00074   // zero the row
00075   for (unsigned int j=0; j<this->n(); j++)
00076     this->el(iv,j) = 0.;
00077 
00078   this->el(iv,jv) = 1.;
00079   rhs.el(iv) = val;
00080   
00081 }

template<typename T >
void DenseMatrix< T >::condense ( const unsigned int  i,
const unsigned int  j,
const T  val,
DenseVector< T > &  rhs 
) [inline]

Condense-out the (i,j) entry of the matrix, forcing it to take on the value val. This is useful in numerical simulations for applying boundary conditions. Preserves the symmetry of the matrix.

Definition at line 265 of file dense_matrix.h.

Referenced by DenseMatrix< Real >::condense().

00269   { DenseMatrixBase<T>::condense (i, j, val, rhs); }

template<typename T >
T DenseMatrix< T >::det (  )  [inline]

Returns:
the determinant of the matrix. Note that this means doing an LU decomposition and then computing the product of the diagonal terms. Therefore this is a non-const method.

Definition at line 492 of file dense_matrix.C.

References DenseMatrix< T >::_decomposition_type, DenseMatrix< T >::_lu_decompose(), DenseMatrix< T >::LU, DenseMatrixBase< T >::m(), and DenseMatrix< T >::NONE.

00493 {
00494   // First LU decompose the matrix (without partial pivoting).
00495   // Note that the lu_decompose routine will check to see if the
00496   // matrix is square so we don't worry about it.
00497   if (this->_decomposition_type == NONE)
00498     this->_lu_decompose(false);
00499   else if (this->_decomposition_type != LU)
00500     {
00501       std::cerr << "Error! Can't compute the determinant under "
00502                 << "the current decomposition."
00503                 << std::endl;
00504       libmesh_error();
00505     }
00506   
00507   // A variable to keep track of the running product of diagonal terms.
00508   T determinant = 1.;
00509   
00510   // Loop over diagonal terms, computing the product.  In practice,
00511   // be careful because this value could easily become too large to
00512   // fit in a double or float.  To be safe, one should keep track of
00513   // the power (of 10) of the determinant in a separate variable
00514   // and maintain an order 1 value for the determinant itself.
00515   for (unsigned int i=0; i<this->m(); i++)
00516     determinant *= (*this)(i,i);
00517 
00518   // Return the determinant
00519   return determinant;
00520 }

template<typename T >
virtual T& DenseMatrix< T >::el ( const unsigned int  i,
const unsigned int  j 
) [inline, virtual]

Returns:
the (i,j) element of the matrix as a writeable reference.

Implements DenseMatrixBase< T >.

Definition at line 96 of file dense_matrix.h.

00097                                            { return (*this)(i,j); } 

template<typename T >
virtual T DenseMatrix< T >::el ( const unsigned int  i,
const unsigned int  j 
) const [inline, virtual]

Returns:
the (i,j) element of the matrix as a writeable reference.

Implements DenseMatrixBase< T >.

Definition at line 90 of file dense_matrix.h.

00091                                            { return (*this)(i,j); }

template<typename T >
void DenseMatrix< T >::get_principal_submatrix ( unsigned int  sub_m,
DenseMatrix< T > &  dest 
) const [inline]

Put the sub_m x sub_m principal submatrix into dest.

Definition at line 278 of file dense_matrix.C.

References DenseMatrix< T >::get_principal_submatrix().

00279 {
00280   get_principal_submatrix(sub_m, sub_m, dest);
00281 }

template<typename T >
void DenseMatrix< T >::get_principal_submatrix ( unsigned int  sub_m,
unsigned int  sub_n,
DenseMatrix< T > &  dest 
) const [inline]

Put the sub_m x sub_n principal submatrix into dest.

Definition at line 263 of file dense_matrix.C.

References DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), and DenseMatrix< T >::resize().

Referenced by DenseMatrix< T >::get_principal_submatrix().

00266 {
00267   libmesh_assert( (sub_m <= this->m()) && (sub_n <= this->n()) );
00268 
00269   dest.resize(sub_m, sub_n);
00270   for(unsigned int i=0; i<sub_m; i++)
00271     for(unsigned int j=0; j<sub_n; j++)
00272       dest(i,j) = (*this)(i,j);
00273 }

template<typename T >
void DenseMatrix< T >::get_transpose ( DenseMatrix< T > &  dest  )  const [inline]

Put the tranposed matrix into dest.

Definition at line 286 of file dense_matrix.C.

References DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), and DenseMatrix< T >::resize().

00287 {
00288   dest.resize(this->n(), this->m());
00289 
00290   for (unsigned int i=0; i<dest.m(); i++)
00291     for (unsigned int j=0; j<dest.n(); j++)
00292       dest(i,j) = (*this)(j,i);
00293 }

template<typename T >
const std::vector<T>& DenseMatrix< T >::get_values (  )  const [inline]

Return a constant reference to the matrix values.

Definition at line 257 of file dense_matrix.h.

00257 { return _val; }

template<typename T >
std::vector<T>& DenseMatrix< T >::get_values (  )  [inline]

Access to the values array. This should be used with caution but can be used to speed up code compilation significantly.

Definition at line 252 of file dense_matrix.h.

Referenced by DenseMatrix< T >::_matvec_blas(), EpetraMatrix< T >::add_matrix(), and PetscMatrix< T >::add_matrix().

00252 { return _val; }

template<typename T >
Real DenseMatrix< T >::l1_norm (  )  const [inline]

Return the l1-norm of the matrix, that is $|M|_1=max_{all columns j}\sum_{all rows i} |M_ij|$, (max. sum of columns). This is the natural matrix norm that is compatible to the l1-norm for vectors, i.e. $|Mv|_1\leq |M|_1 |v|_1$.

Definition at line 723 of file dense_matrix.h.

References DenseMatrixBase< T >::_m, and DenseMatrixBase< T >::_n.

Referenced by FEMSystem::assembly().

00724 {
00725   libmesh_assert (this->_m);
00726   libmesh_assert (this->_n);
00727 
00728   Real columnsum = 0.;
00729   for (unsigned int i=0; i!=this->_m; i++)
00730     {
00731       columnsum += std::abs((*this)(i,0));
00732     }
00733   Real my_max = columnsum;
00734   for (unsigned int j=1; j!=this->_n; j++)
00735     {
00736       columnsum = 0.;
00737       for (unsigned int i=0; i!=this->_m; i++)
00738         {
00739           columnsum += std::abs((*this)(i,j));
00740         }
00741       my_max = (my_max > columnsum? my_max : columnsum);
00742     }
00743   return my_max;
00744 }

template<typename T >
void DenseMatrix< T >::left_multiply ( const DenseMatrixBase< T > &  M2  )  [inline, virtual]

Left multipliess by the matrix M2.

Implements DenseMatrixBase< T >.

Definition at line 35 of file dense_matrix.C.

References DenseMatrix< T >::_multiply_blas(), DenseMatrix< T >::LEFT_MULTIPLY, DenseMatrixBase< T >::m(), DenseMatrixBase< T >::multiply(), DenseMatrixBase< T >::n(), DenseMatrix< T >::resize(), and DenseMatrix< T >::use_blas_lapack.

00036 {
00037   if (this->use_blas_lapack)
00038     this->_multiply_blas(M2, LEFT_MULTIPLY);
00039   else
00040     {
00041       // (*this) <- M2 * (*this)
00042       // Where:
00043       // (*this) = (m x n),
00044       // M2      = (m x p),
00045       // M3      = (p x n)
00046   
00047       // M3 is a copy of *this before it gets resize()d
00048       DenseMatrix<T> M3(*this);
00049 
00050       // Resize *this so that the result can fit
00051       this->resize (M2.m(), M3.n());
00052 
00053       // Call the multiply function in the base class
00054       this->multiply(*this, M2, M3);
00055     }
00056 }

template<typename T >
void DenseMatrix< T >::left_multiply_transpose ( const DenseMatrix< T > &  A  )  [inline]

Left multiplies by the transpose of the matrix A.

Definition at line 62 of file dense_matrix.C.

References DenseMatrix< T >::_multiply_blas(), DenseMatrix< T >::LEFT_MULTIPLY_TRANSPOSE, DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), DenseMatrix< T >::resize(), DenseMatrix< T >::transpose(), and DenseMatrix< T >::use_blas_lapack.

Referenced by DofMap::constrain_element_matrix(), and DofMap::constrain_element_matrix_and_vector().

00063 {
00064   if (this->use_blas_lapack)
00065     this->_multiply_blas(A, LEFT_MULTIPLY_TRANSPOSE);
00066   else
00067     {
00068       //Check to see if we are doing (A^T)*A
00069       if (this == &A)
00070         {
00071           //libmesh_here();
00072           DenseMatrix<T> B(*this);
00073       
00074           // Simple but inefficient way
00075           // return this->left_multiply_transpose(B);
00076 
00077           // More efficient, but more code way
00078           // If A is mxn, the result will be a square matrix of Size n x n.
00079           const unsigned int m = A.m();
00080           const unsigned int n = A.n();
00081 
00082           // resize() *this and also zero out all entries.
00083           this->resize(n,n);
00084 
00085           // Compute the lower-triangular part
00086           for (unsigned int i=0; i<n; ++i)
00087             for (unsigned int j=0; j<=i; ++j)
00088               for (unsigned int k=0; k<m; ++k) // inner products are over m
00089                 (*this)(i,j) += B(k,i)*B(k,j);
00090 
00091           // Copy lower-triangular part into upper-triangular part
00092           for (unsigned int i=0; i<n; ++i)
00093             for (unsigned int j=i+1; j<n; ++j)
00094               (*this)(i,j) = (*this)(j,i);
00095         }
00096 
00097       else
00098         {
00099           DenseMatrix<T> B(*this);
00100   
00101           this->resize (A.n(), B.n());
00102       
00103           libmesh_assert (A.m() == B.m());
00104           libmesh_assert (this->m() == A.n());
00105           libmesh_assert (this->n() == B.n());
00106       
00107           const unsigned int m_s = A.n();
00108           const unsigned int p_s = A.m(); 
00109           const unsigned int n_s = this->n();
00110   
00111           // Do it this way because there is a
00112           // decent chance (at least for constraint matrices)
00113           // that A.transpose(i,k) = 0.
00114           for (unsigned int i=0; i<m_s; i++)
00115             for (unsigned int k=0; k<p_s; k++)
00116               if (A.transpose(i,k) != 0.)
00117                 for (unsigned int j=0; j<n_s; j++)
00118                   (*this)(i,j) += A.transpose(i,k)*B(k,j);
00119         }
00120     }
00121   
00122 }

template<typename T >
Real DenseMatrix< T >::linfty_norm (  )  const [inline]

Return the linfty-norm of the matrix, that is $|M|_\infty=max_{all rows i}\sum_{all columns j} |M_ij|$, (max. sum of rows). This is the natural matrix norm that is compatible to the linfty-norm of vectors, i.e. $|Mv|_\infty \leq |M|_\infty |v|_\infty$.

Definition at line 750 of file dense_matrix.h.

References DenseMatrixBase< T >::_m, and DenseMatrixBase< T >::_n.

00751 {
00752   libmesh_assert (this->_m);
00753   libmesh_assert (this->_n);
00754 
00755   Real rowsum = 0.;
00756   for (unsigned int j=0; j!=this->_n; j++)
00757     {
00758       rowsum += std::abs((*this)(0,j));
00759     }
00760   Real my_max = rowsum;
00761   for (unsigned int i=1; i!=this->_m; i++)
00762     {
00763       rowsum = 0.;
00764       for (unsigned int j=0; j!=this->_n; j++)
00765         {
00766           rowsum += std::abs((*this)(i,j));
00767         }
00768       my_max = (my_max > rowsum? my_max : rowsum);
00769     }
00770   return my_max;
00771 }

template<typename T >
void DenseMatrix< T >::lu_solve ( DenseVector< T > &  b,
DenseVector< T > &  x,
const bool  partial_pivot = false 
) [inline]

Solve the system Ax=b given the input vector b.

Definition at line 299 of file dense_matrix.C.

References DenseMatrix< T >::_decomposition_type, DenseMatrix< T >::_lu_back_substitute(), DenseMatrix< T >::_lu_back_substitute_lapack(), DenseMatrix< T >::_lu_decompose(), DenseMatrix< T >::_lu_decompose_lapack(), DenseMatrix< T >::LU, DenseMatrix< T >::LU_BLAS_LAPACK, DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), DenseMatrix< T >::NONE, and DenseMatrix< T >::use_blas_lapack.

Referenced by PatchRecoveryErrorEstimator::EstimateError::operator()().

00302 {
00303   // Check to be sure that the matrix is square before attempting
00304   // an LU-solve.  In general, one can compute the LU factorization of
00305   // a non-square matrix, but:
00306   //
00307   // Overdetermined systems (m>n) have a solution only if enough of
00308   // the equations are linearly-dependent.
00309   //
00310   // Underdetermined systems (m<n) typically have infinitely many
00311   // solutions.
00312   // 
00313   // We don't want to deal with either of these ambiguous cases here...
00314   if (this->m() != this->n())
00315     {
00316       std::cout << "Error! LU solve only works for square matrices!"
00317                 << std::endl;
00318       libmesh_error();
00319     }
00320 
00321 
00322   switch(this->_decomposition_type)
00323     {
00324     case NONE:
00325       {
00326         if (this->use_blas_lapack)
00327           this->_lu_decompose_lapack();   
00328         else
00329           this->_lu_decompose (partial_pivot);
00330         break;
00331       }
00332 
00333     case LU_BLAS_LAPACK:
00334       {
00335         // Already factored, just need to call back_substitute.
00336         if (this->use_blas_lapack)
00337           break;
00338       }
00339 
00340     case LU:
00341       {
00342         // Already factored, just need to call back_substitute.
00343         if ( !(this->use_blas_lapack) )
00344           break;
00345       }
00346 
00347     default:
00348       {
00349         std::cerr << "Error! This matrix already has a "
00350                   << "different decomposition..."
00351                   << std::endl;
00352         libmesh_error();
00353       }
00354     }
00355 
00356   if (this->use_blas_lapack)
00357      this->_lu_back_substitute_lapack (b, x);
00358   else
00359     this->_lu_back_substitute (b, x, partial_pivot);
00360 }

template<typename T >
unsigned int DenseMatrixBase< T >::m (  )  const [inline, inherited]

template<typename T >
Real DenseMatrix< T >::max (  )  const [inline]

Returns:
the maximum element in the matrix. In case of complex numbers, this returns the maximum Real part.

Definition at line 702 of file dense_matrix.h.

References DenseMatrixBase< T >::_m, DenseMatrixBase< T >::_n, and libmesh_real().

00703 {
00704   libmesh_assert (this->_m);
00705   libmesh_assert (this->_n);
00706   Real my_max = libmesh_real((*this)(0,0));
00707 
00708   for (unsigned int i=0; i!=this->_m; i++)
00709     {
00710       for (unsigned int j=0; j!=this->_n; j++)
00711         {
00712           Real current = libmesh_real((*this)(i,j));
00713           my_max = (my_max > current? my_max : current);
00714         }
00715     }
00716   return my_max;
00717 }

template<typename T >
Real DenseMatrix< T >::min (  )  const [inline]

Returns:
the minimum element in the matrix. In case of complex numbers, this returns the minimum Real part.

Definition at line 681 of file dense_matrix.h.

References DenseMatrixBase< T >::_m, DenseMatrixBase< T >::_n, and libmesh_real().

00682 {
00683   libmesh_assert (this->_m);
00684   libmesh_assert (this->_n);
00685   Real my_min = libmesh_real((*this)(0,0));
00686 
00687   for (unsigned int i=0; i!=this->_m; i++)
00688     {
00689       for (unsigned int j=0; j!=this->_n; j++)
00690         {
00691           Real current = libmesh_real((*this)(i,j));
00692           my_min = (my_min < current? my_min : current);
00693         }
00694     }
00695   return my_min;
00696 }

template<typename T >
void DenseMatrixBase< T >::multiply ( DenseMatrixBase< T > &  M1,
const DenseMatrixBase< T > &  M2,
const DenseMatrixBase< T > &  M3 
) [inline, protected, inherited]

Performs the computation M1 = M2 * M3 where: M1 = (m x n) M2 = (m x p) M3 = (p x n)

Definition at line 30 of file dense_matrix_base.C.

References DenseMatrixBase< T >::el(), DenseMatrixBase< T >::m(), and DenseMatrixBase< T >::n().

Referenced by DenseMatrix< T >::left_multiply(), and DenseMatrix< T >::right_multiply().

00033 {
00034   // Assertions to make sure we have been
00035   // passed matrices of the correct dimension.
00036   libmesh_assert (M1.m() == M2.m());
00037   libmesh_assert (M1.n() == M3.n());
00038   libmesh_assert (M2.n() == M3.m());
00039           
00040   const unsigned int m_s = M2.m();
00041   const unsigned int p_s = M2.n(); 
00042   const unsigned int n_s = M1.n();
00043   
00044   // Do it this way because there is a
00045   // decent chance (at least for constraint matrices)
00046   // that M3(k,j) = 0. when right-multiplying.
00047   for (unsigned int k=0; k<p_s; k++)
00048     for (unsigned int j=0; j<n_s; j++)
00049       if (M3.el(k,j) != 0.)
00050         for (unsigned int i=0; i<m_s; i++)
00051           M1.el(i,j) += M2.el(i,k) * M3.el(k,j);                  
00052 }

template<typename T >
bool DenseMatrix< T >::operator!= ( const DenseMatrix< T > &  mat  )  const [inline]

Tests if mat is not exactly equal to this matrix.

Definition at line 644 of file dense_matrix.h.

References DenseMatrix< T >::_val.

00645 {
00646   for (unsigned int i=0; i<_val.size(); i++)
00647     if (_val[i] != mat._val[i])
00648       return true;
00649 
00650   return false;
00651 }

template<typename T >
T & DenseMatrix< T >::operator() ( const unsigned int  i,
const unsigned int  j 
) [inline]

Returns:
the (i,j) element of the matrix as a writeable reference.

Definition at line 584 of file dense_matrix.h.

References DenseMatrixBase< T >::_m, DenseMatrixBase< T >::_n, and DenseMatrix< T >::_val.

00586 {
00587   libmesh_assert (i*j<_val.size());
00588   libmesh_assert (i < this->_m);
00589   libmesh_assert (j < this->_n);
00590   
00591   //return _val[(i) + (this->_m)*(j)]; // col-major
00592   return _val[(i)*(this->_n) + (j)]; // row-major
00593 }

template<typename T >
T DenseMatrix< T >::operator() ( const unsigned int  i,
const unsigned int  j 
) const [inline]

Returns:
the (i,j) element of the matrix.

Definition at line 568 of file dense_matrix.h.

References DenseMatrixBase< T >::_m, DenseMatrixBase< T >::_n, and DenseMatrix< T >::_val.

00570 {
00571   libmesh_assert (i*j<_val.size());
00572   libmesh_assert (i < this->_m);
00573   libmesh_assert (j < this->_n);
00574   
00575   
00576   //  return _val[(i) + (this->_m)*(j)]; // col-major
00577   return _val[(i)*(this->_n) + (j)]; // row-major
00578 }

template<typename T >
DenseMatrix< T > & DenseMatrix< T >::operator*= ( const T  factor  )  [inline]

Multiplies every element in the matrix by factor.

Definition at line 611 of file dense_matrix.h.

References DenseMatrix< T >::scale().

00612 {
00613   this->scale(factor);
00614   return *this;
00615 }

template<typename T >
DenseMatrix< T > & DenseMatrix< T >::operator+= ( const DenseMatrix< T > &  mat  )  [inline]

Adds mat to this matrix.

Definition at line 657 of file dense_matrix.h.

References DenseMatrix< T >::_val.

00658 {
00659   for (unsigned int i=0; i<_val.size(); i++)
00660     _val[i] += mat._val[i];
00661 
00662   return *this;
00663 }

template<typename T >
DenseMatrix< T > & DenseMatrix< T >::operator-= ( const DenseMatrix< T > &  mat  )  [inline]

Subtracts mat from this matrix.

Definition at line 669 of file dense_matrix.h.

References DenseMatrix< T >::_val.

00670 {
00671   for (unsigned int i=0; i<_val.size(); i++)
00672     _val[i] -= mat._val[i];
00673 
00674   return *this;
00675 }

template<typename T >
DenseMatrix< T > & DenseMatrix< T >::operator= ( const DenseMatrix< T > &  other_matrix  )  [inline]

Assignment operator.

Definition at line 553 of file dense_matrix.h.

References DenseMatrix< T >::_decomposition_type, DenseMatrixBase< T >::_m, DenseMatrixBase< T >::_n, and DenseMatrix< T >::_val.

00554 {
00555   this->_m = other_matrix._m;
00556   this->_n = other_matrix._n;
00557 
00558   _val                = other_matrix._val;
00559   _decomposition_type = other_matrix._decomposition_type;
00560 
00561   return *this;
00562 }

template<typename T >
bool DenseMatrix< T >::operator== ( const DenseMatrix< T > &  mat  )  const [inline]

Tests if mat is exactly equal to this matrix.

Definition at line 631 of file dense_matrix.h.

References DenseMatrix< T >::_val.

00632 {
00633   for (unsigned int i=0; i<_val.size(); i++)
00634     if (_val[i] != mat._val[i])
00635       return false;
00636 
00637   return true;
00638 }

template<typename T >
void DenseMatrixBase< T >::print ( std::ostream &  os  )  const [inline, inherited]

Pretty-print the matrix to stdout.

Definition at line 127 of file dense_matrix_base.C.

References DenseMatrixBase< T >::el(), DenseMatrixBase< T >::m(), and DenseMatrixBase< T >::n().

00128 {  
00129   for (unsigned int i=0; i<this->m(); i++)
00130     {
00131       for (unsigned int j=0; j<this->n(); j++)
00132         os << std::setw(8)
00133            << this->el(i,j) << " ";
00134 
00135       os << std::endl;
00136     }
00137 
00138   return;
00139 }

template<typename T >
void DenseMatrixBase< T >::print_scientific ( std::ostream &  os  )  const [inline, inherited]

Prints the matrix entries with more decimal places in scientific notation.

Definition at line 85 of file dense_matrix_base.C.

References DenseMatrixBase< T >::el(), DenseMatrixBase< T >::m(), and DenseMatrixBase< T >::n().

00086 {
00087 #ifndef LIBMESH_BROKEN_IOSTREAM
00088   
00089   // save the initial format flags
00090   std::ios_base::fmtflags os_flags = os.flags();
00091   
00092   // Print the matrix entries.
00093   for (unsigned int i=0; i<this->m(); i++)
00094     {
00095       for (unsigned int j=0; j<this->n(); j++)
00096         os << std::setw(15)
00097            << std::scientific
00098            << std::setprecision(8)
00099            << this->el(i,j) << " ";
00100 
00101       os << std::endl;
00102     }
00103   
00104   // reset the original format flags
00105   os.flags(os_flags);
00106 
00107 #else
00108   
00109   // Print the matrix entries.
00110   for (unsigned int i=0; i<this->m(); i++)
00111     {
00112       for (unsigned int j=0; j<this->n(); j++)  
00113         os << std::setprecision(8)
00114            << this->el(i,j)
00115            << " ";
00116       
00117       os << std::endl;
00118     }
00119   
00120   
00121 #endif
00122 }

template<typename T >
void DenseMatrix< T >::right_multiply ( const DenseMatrixBase< T > &  M3  )  [inline, virtual]

Right multiplies by the matrix M3.

Implements DenseMatrixBase< T >.

Definition at line 130 of file dense_matrix.C.

References DenseMatrix< T >::_multiply_blas(), DenseMatrixBase< T >::m(), DenseMatrixBase< T >::multiply(), DenseMatrixBase< T >::n(), DenseMatrix< T >::resize(), DenseMatrix< T >::RIGHT_MULTIPLY, and DenseMatrix< T >::use_blas_lapack.

Referenced by DofMap::build_constraint_matrix(), DofMap::constrain_element_matrix(), and DofMap::constrain_element_matrix_and_vector().

00131 {
00132   if (this->use_blas_lapack)
00133     this->_multiply_blas(M3, RIGHT_MULTIPLY);
00134   else
00135     {
00136       // (*this) <- M3 * (*this)
00137       // Where:
00138       // (*this) = (m x n),
00139       // M2      = (m x p),
00140       // M3      = (p x n)
00141 
00142       // M2 is a copy of *this before it gets resize()d
00143       DenseMatrix<T> M2(*this);
00144 
00145       // Resize *this so that the result can fit
00146       this->resize (M2.m(), M3.n());
00147   
00148       this->multiply(*this, M2, M3);
00149     }
00150 }

template<typename T >
void DenseMatrix< T >::right_multiply_transpose ( const DenseMatrix< T > &  A  )  [inline]

Right multiplies by the transpose of the matrix A

Definition at line 156 of file dense_matrix.C.

References DenseMatrix< T >::_multiply_blas(), DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), DenseMatrix< T >::resize(), DenseMatrix< T >::RIGHT_MULTIPLY_TRANSPOSE, DenseMatrix< T >::transpose(), and DenseMatrix< T >::use_blas_lapack.

00157 {
00158   if (this->use_blas_lapack)
00159     this->_multiply_blas(B, RIGHT_MULTIPLY_TRANSPOSE);
00160   else
00161     {
00162       //Check to see if we are doing B*(B^T)
00163       if (this == &B)
00164         {
00165           //libmesh_here();
00166           DenseMatrix<T> A(*this);
00167       
00168           // Simple but inefficient way
00169           // return this->right_multiply_transpose(A);
00170 
00171           // More efficient, more code
00172           // If B is mxn, the result will be a square matrix of Size m x m.
00173           const unsigned int m = B.m();
00174           const unsigned int n = B.n();
00175 
00176           // resize() *this and also zero out all entries.
00177           this->resize(m,m);
00178 
00179           // Compute the lower-triangular part
00180           for (unsigned int i=0; i<m; ++i)
00181             for (unsigned int j=0; j<=i; ++j)
00182               for (unsigned int k=0; k<n; ++k) // inner products are over n
00183                 (*this)(i,j) += A(i,k)*A(j,k);
00184 
00185           // Copy lower-triangular part into upper-triangular part
00186           for (unsigned int i=0; i<m; ++i)
00187             for (unsigned int j=i+1; j<m; ++j)
00188               (*this)(i,j) = (*this)(j,i);
00189         }
00190 
00191       else
00192         {
00193           DenseMatrix<T> A(*this);
00194   
00195           this->resize (A.m(), B.m());
00196       
00197           libmesh_assert (A.n() == B.n());
00198           libmesh_assert (this->m() == A.m());
00199           libmesh_assert (this->n() == B.m());
00200       
00201           const unsigned int m_s = A.m();
00202           const unsigned int p_s = A.n(); 
00203           const unsigned int n_s = this->n();
00204 
00205           // Do it this way because there is a
00206           // decent chance (at least for constraint matrices)
00207           // that B.transpose(k,j) = 0.
00208           for (unsigned int j=0; j<n_s; j++)
00209             for (unsigned int k=0; k<p_s; k++)
00210               if (B.transpose(k,j) != 0.)
00211                 for (unsigned int i=0; i<m_s; i++)
00212                   (*this)(i,j) += A(i,k)*B.transpose(k,j);
00213         }
00214     }
00215 }

template<typename T >
void DenseMatrix< T >::scale ( const T  factor  )  [inline]

Multiplies every element in the matrix by factor.

Definition at line 601 of file dense_matrix.h.

References DenseMatrix< T >::_val.

Referenced by DenseMatrix< T >::operator*=().

00602 {
00603   for (unsigned int i=0; i<_val.size(); i++)
00604     _val[i] *= factor;
00605 }

template<typename T >
void DenseMatrix< T >::swap ( DenseMatrix< T > &  other_matrix  )  [inline]

STL-like swap method

Definition at line 512 of file dense_matrix.h.

References DenseMatrix< T >::_decomposition_type, DenseMatrixBase< T >::_m, DenseMatrixBase< T >::_n, and DenseMatrix< T >::_val.

Referenced by DenseMatrix< T >::_multiply_blas(), and FEMSystem::assembly().

00513 {
00514   std::swap(this->_m, other_matrix._m);
00515   std::swap(this->_n, other_matrix._n);
00516   _val.swap(other_matrix._val);
00517   DecompositionType _temp = _decomposition_type;
00518   _decomposition_type = other_matrix._decomposition_type;
00519   other_matrix._decomposition_type = _temp;
00520 }

template<typename T >
T DenseMatrix< T >::transpose ( const unsigned int  i,
const unsigned int  j 
) const [inline]

Returns:
the (i,j) element of the transposed matrix.

Definition at line 777 of file dense_matrix.h.

Referenced by DofMap::constrain_element_dyad_matrix(), DofMap::constrain_element_matrix_and_vector(), DofMap::constrain_element_vector(), DenseMatrix< T >::left_multiply_transpose(), and DenseMatrix< T >::right_multiply_transpose().

00779 {
00780   // Implement in terms of operator()
00781   return (*this)(j,i);
00782 }

template<typename T >
void DenseMatrix< T >::vector_mult ( DenseVector< T > &  dest,
const DenseVector< T > &  arg 
) const [inline]

Performs the matrix-vector multiplication, dest := (*this) * arg.

Definition at line 220 of file dense_matrix.C.

References DenseMatrix< T >::_matvec_blas(), DenseMatrixBase< T >::m(), DenseMatrixBase< T >::n(), DenseVector< T >::resize(), DenseVector< T >::size(), and DenseMatrix< T >::use_blas_lapack.

Referenced by DenseMatrix< T >::vector_mult_add().

00222 {
00223   // Make sure the input sizes are compatible
00224   libmesh_assert(this->n() == arg.size());
00225 
00226   // Resize and clear dest.
00227   // Note: DenseVector::resize() also zeros the vector.
00228   dest.resize(this->m());
00229 
00230   if (this->use_blas_lapack)
00231     this->_matvec_blas(1., 0., dest, arg);
00232   else
00233     {
00234       const unsigned int n_rows = this->m();
00235       const unsigned int n_cols = this->n();
00236 
00237       for(unsigned int i=0; i<n_rows; i++)
00238         for(unsigned int j=0; j<n_cols; j++)
00239           dest(i) += (*this)(i,j)*arg(j);
00240     }
00241 }

template<typename T >
void DenseMatrix< T >::vector_mult_add ( DenseVector< T > &  dest,
const T  factor,
const DenseVector< T > &  arg 
) const [inline]

Performs the scaled matrix-vector multiplication, dest += factor * (*this) * arg.

Definition at line 246 of file dense_matrix.C.

References DenseMatrix< T >::_matvec_blas(), DenseVector< T >::add(), DenseVector< T >::size(), DenseMatrix< T >::use_blas_lapack, and DenseMatrix< T >::vector_mult().

00249 {
00250   if (this->use_blas_lapack)
00251     this->_matvec_blas(factor, 1., dest, arg);
00252   else
00253     {
00254       DenseVector<T> temp(arg.size());
00255       this->vector_mult(temp, arg);
00256       dest.add(factor, temp);
00257     }
00258 }

template<typename T >
void DenseMatrix< T >::zero (  )  [inline, virtual]

Set every element in the matrix to 0.

Implements DenseMatrixBase< T >.

Definition at line 542 of file dense_matrix.h.

References DenseMatrix< T >::_decomposition_type, DenseMatrix< T >::_val, and DenseMatrix< T >::NONE.

Referenced by FEBase::coarsened_dof_values(), System::ProjectVector::operator()(), and DenseMatrix< T >::resize().

00543 {
00544   _decomposition_type = NONE;
00545 
00546   std::fill (_val.begin(), _val.end(), 0.);
00547 }


Friends And Related Function Documentation

template<typename T >
std::ostream& operator<< ( std::ostream &  os,
const DenseMatrixBase< T > &  m 
) [friend, inherited]

Formatted print as above but allows you to do DenseMatrix K; std::cout << K << std::endl;

Definition at line 115 of file dense_matrix_base.h.

00116   {
00117     m.print(os);
00118     return os;
00119   }


Member Data Documentation

template<typename T >
std::vector<int> DenseMatrix< T >::_pivots [private]

This array is used to store pivot indices. May be used by whatever factorization is currently active, clients of the class should not rely on it for any reason.

Definition at line 411 of file dense_matrix.h.

Referenced by DenseMatrix< T >::_lu_back_substitute_lapack(), and DenseMatrix< T >::_lu_decompose_lapack().

template<typename T >
bool DenseMatrix< T >::use_blas_lapack

Computes the inverse of the dense matrix (assuming it is invertible) by first computing the LU decomposition and then performing multiple back substitution steps. Follows the algorithm from Numerical Recipes in C available on the web. This is not the most memory efficient routine since the inverse is not computed "in place" but is instead placed into a the matrix inv passed in by the user. Run-time selectable option to turn on/off blas support. This was primarily used for testing purposes, and could be removed...

Definition at line 316 of file dense_matrix.h.

Referenced by DenseMatrix< T >::left_multiply(), DenseMatrix< T >::left_multiply_transpose(), DenseMatrix< T >::lu_solve(), DenseMatrix< T >::right_multiply(), DenseMatrix< T >::right_multiply_transpose(), DenseMatrix< T >::vector_mult(), and DenseMatrix< T >::vector_mult_add().


The documentation for this class was generated from the following files:

Site Created By: libMesh Developers
Last modified: November 25 2009 03:44:02.

Hosted By:
SourceForge.net Logo