libMesh
Public Member Functions | Public Attributes | Protected Member Functions | Static Protected Member Functions | Protected Attributes | Private Types | Private Member Functions | Private Attributes | List of all members
libMesh::DenseMatrix< T > Class Template Reference

Defines a dense matrix for use in Finite Element-type computations. More...

#include <dof_map.h>

Inheritance diagram for libMesh::DenseMatrix< T >:
[legend]

Public Member Functions

 DenseMatrix (const unsigned int new_m=0, const unsigned int new_n=0)
 Constructor. More...
 
 DenseMatrix (DenseMatrix &&)=default
 The 5 special functions can be defaulted for this class, as it does not manage any memory itself. More...
 
 DenseMatrix (const DenseMatrix &)=default
 
DenseMatrixoperator= (const DenseMatrix &)=default
 
DenseMatrixoperator= (DenseMatrix &&)=default
 
virtual ~DenseMatrix ()=default
 
virtual void zero () override
 Set every element in the matrix to 0. More...
 
DenseMatrix sub_matrix (unsigned int row_id, unsigned int row_size, unsigned int col_id, unsigned int col_size) const
 Get submatrix with the smallest row and column indices and the submatrix size. More...
 
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 override
 
virtual T & el (const unsigned int i, const unsigned int j) override
 
virtual void left_multiply (const DenseMatrixBase< T > &M2) override
 Performs the operation: (*this) <- M2 * (*this) More...
 
template<typename T2 >
void left_multiply (const DenseMatrixBase< T2 > &M2)
 Left multiplies by the matrix M2 of different type. More...
 
virtual void right_multiply (const DenseMatrixBase< T > &M2) override
 Performs the operation: (*this) <- (*this) * M3. More...
 
template<typename T2 >
void right_multiply (const DenseMatrixBase< T2 > &M2)
 Right multiplies by the matrix M2 of different type. More...
 
void vector_mult (DenseVector< T > &dest, const DenseVector< T > &arg) const
 Performs the matrix-vector multiplication, dest := (*this) * arg. More...
 
template<typename T2 >
void vector_mult (DenseVector< typename CompareTypes< T, T2 >::supertype > &dest, const DenseVector< T2 > &arg) const
 Performs the matrix-vector multiplication, dest := (*this) * arg on mixed types. More...
 
void vector_mult_transpose (DenseVector< T > &dest, const DenseVector< T > &arg) const
 Performs the matrix-vector multiplication, dest := (*this)^T * arg. More...
 
template<typename T2 >
void vector_mult_transpose (DenseVector< typename CompareTypes< T, T2 >::supertype > &dest, const DenseVector< T2 > &arg) const
 Performs the matrix-vector multiplication, dest := (*this)^T * arg. More...
 
void vector_mult_add (DenseVector< T > &dest, const T factor, const DenseVector< T > &arg) const
 Performs the scaled matrix-vector multiplication, dest += factor * (*this) * arg. More...
 
template<typename T2 , typename T3 >
void vector_mult_add (DenseVector< typename CompareTypes< T, typename CompareTypes< T2, T3 >::supertype >::supertype > &dest, const T2 factor, const DenseVector< T3 > &arg) const
 Performs the scaled matrix-vector multiplication, dest += factor * (*this) * arg. More...
 
void get_principal_submatrix (unsigned int sub_m, unsigned int sub_n, DenseMatrix< T > &dest) const
 Put the sub_m x sub_n principal submatrix into dest. More...
 
void get_principal_submatrix (unsigned int sub_m, DenseMatrix< T > &dest) const
 Put the sub_m x sub_m principal submatrix into dest. More...
 
void outer_product (const DenseVector< T > &a, const DenseVector< T > &b)
 Computes the outer (dyadic) product of two vectors and stores in (*this). More...
 
template<typename T2 >
DenseMatrix< T > & operator= (const DenseMatrix< T2 > &other_matrix)
 Assignment-from-other-matrix-type operator. More...
 
void swap (DenseMatrix< T > &other_matrix)
 STL-like swap method. More...
 
void resize (const unsigned int new_m, const unsigned int new_n)
 Resize the matrix. More...
 
void scale (const T factor)
 Multiplies every element in the matrix by factor. More...
 
void scale_column (const unsigned int col, const T factor)
 Multiplies every element in the column col matrix by factor. More...
 
DenseMatrix< T > & operator*= (const T factor)
 Multiplies every element in the matrix by factor. More...
 
template<typename T2 , typename T3 >
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type add (const T2 factor, const DenseMatrix< T3 > &mat)
 Adds factor times mat to this matrix. More...
 
bool operator== (const DenseMatrix< T > &mat) const
 
bool operator!= (const DenseMatrix< T > &mat) const
 
DenseMatrix< T > & operator+= (const DenseMatrix< T > &mat)
 Adds mat to this matrix. More...
 
DenseMatrix< T > & operator-= (const DenseMatrix< T > &mat)
 Subtracts mat from this matrix. More...
 
auto min () const -> decltype(libmesh_real(T(0)))
 
auto max () const -> decltype(libmesh_real(T(0)))
 
auto l1_norm () const -> decltype(std::abs(T(0)))
 
auto linfty_norm () const -> decltype(std::abs(T(0)))
 
void left_multiply_transpose (const DenseMatrix< T > &A)
 Left multiplies by the transpose of the matrix A. More...
 
template<typename T2 >
void left_multiply_transpose (const DenseMatrix< T2 > &A)
 Left multiplies by the transpose of the matrix A which contains a different numerical type. More...
 
void right_multiply_transpose (const DenseMatrix< T > &A)
 Right multiplies by the transpose of the matrix A. More...
 
template<typename T2 >
void right_multiply_transpose (const DenseMatrix< T2 > &A)
 Right multiplies by the transpose of the matrix A which contains a different numerical type. More...
 
transpose (const unsigned int i, const unsigned int j) const
 
void get_transpose (DenseMatrix< T > &dest) const
 Put the tranposed matrix into dest. More...
 
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)
 Condense-out the (i,j) entry of the matrix, forcing it to take on the value val. More...
 
void lu_solve (const DenseVector< T > &b, DenseVector< T > &x)
 Solve the system Ax=b given the input vector b. More...
 
template<typename T2 >
void cholesky_solve (const DenseVector< T2 > &b, DenseVector< T2 > &x)
 For symmetric positive definite (SPD) matrices. More...
 
void svd (DenseVector< Real > &sigma)
 Compute the singular value decomposition of the matrix. More...
 
void svd (DenseVector< Real > &sigma, DenseMatrix< Number > &U, DenseMatrix< Number > &VT)
 Compute the "reduced" singular value decomposition of the matrix. More...
 
void svd_solve (const DenseVector< T > &rhs, DenseVector< T > &x, Real rcond=std::numeric_limits< Real >::epsilon()) const
 Solve the system of equations \( A x = rhs \) for \( x \) in the least-squares sense. More...
 
void evd (DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag)
 Compute the eigenvalues (both real and imaginary parts) of a general matrix. More...
 
void evd_left (DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > &VL)
 Compute the eigenvalues (both real and imaginary parts) and left eigenvectors of a general matrix, \( A \). More...
 
void evd_right (DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > &VR)
 Compute the eigenvalues (both real and imaginary parts) and right eigenvectors of a general matrix, \( A \). More...
 
void evd_left_and_right (DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > &VL, DenseMatrix< T > &VR)
 Compute the eigenvalues (both real and imaginary parts) as well as the left and right eigenvectors of a general matrix. More...
 
det ()
 
unsigned int m () const
 
unsigned int n () const
 
void print (std::ostream &os=libMesh::out) const
 Pretty-print the matrix, by default to libMesh::out. More...
 
void print_scientific (std::ostream &os, unsigned precision=8) const
 Prints the matrix entries with more decimal places in scientific notation. More...
 
template<typename T2 , typename T3 >
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type add (const T2 factor, const DenseMatrixBase< T3 > &mat)
 Adds factor to every element in the matrix. More...
 
DenseVector< T > diagonal () const
 Return the matrix diagonal. More...
 

Public Attributes

bool 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. More...
 

Protected Member Functions

void condense (const unsigned int i, const unsigned int j, const T val, DenseVectorBase< T > &rhs)
 Condense-out the (i,j) entry of the matrix, forcing it to take on the value val. More...
 

Static Protected Member Functions

static void multiply (DenseMatrixBase< T > &M1, const DenseMatrixBase< T > &M2, const DenseMatrixBase< T > &M3)
 Helper function - Performs the computation M1 = M2 * M3 where: M1 = (m x n) M2 = (m x p) M3 = (p x n) More...
 

Protected Attributes

unsigned int _m
 The row dimension. More...
 
unsigned int _n
 The column dimension. More...
 

Private Types

enum  DecompositionType { LU =0, CHOLESKY =1, LU_BLAS_LAPACK, NONE }
 The decomposition schemes above change the entries of the matrix A. More...
 
enum  _BLAS_Multiply_Flag { LEFT_MULTIPLY = 0, RIGHT_MULTIPLY, LEFT_MULTIPLY_TRANSPOSE, RIGHT_MULTIPLY_TRANSPOSE }
 Enumeration used to determine the behavior of the _multiply_blas function. More...
 
typedef PetscBLASInt pivot_index_t
 Array used to store pivot indices. More...
 
typedef int pivot_index_t
 

Private Member Functions

void _lu_decompose ()
 Form the LU decomposition of the matrix. More...
 
void _lu_back_substitute (const DenseVector< T > &b, DenseVector< T > &x) const
 Solves the system Ax=b through back substitution. More...
 
void _cholesky_decompose ()
 Decomposes a symmetric positive definite matrix into a product of two lower triangular matrices according to A = LL^T. More...
 
template<typename T2 >
void _cholesky_back_substitute (const DenseVector< T2 > &b, DenseVector< T2 > &x) const
 Solves the equation Ax=b for the unknown value x and rhs b based on the Cholesky factorization of A. More...
 
void _multiply_blas (const DenseMatrixBase< T > &other, _BLAS_Multiply_Flag flag)
 The _multiply_blas function computes A <- op(A) * op(B) using BLAS gemm function. More...
 
void _lu_decompose_lapack ()
 Computes an LU factorization of the matrix using the Lapack routine "getrf". More...
 
void _svd_lapack (DenseVector< Real > &sigma)
 Computes an SVD of the matrix using the Lapack routine "getsvd". More...
 
void _svd_lapack (DenseVector< Real > &sigma, DenseMatrix< Number > &U, DenseMatrix< Number > &VT)
 Computes a "reduced" SVD of the matrix using the Lapack routine "getsvd". More...
 
void _svd_solve_lapack (const DenseVector< T > &rhs, DenseVector< T > &x, Real rcond) const
 Called by svd_solve(rhs). More...
 
void _svd_helper (char JOBU, char JOBVT, std::vector< Real > &sigma_val, std::vector< Number > &U_val, std::vector< Number > &VT_val)
 Helper function that actually performs the SVD. More...
 
void _evd_lapack (DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > *VL=nullptr, DenseMatrix< T > *VR=nullptr)
 Computes the eigenvalues of the matrix using the Lapack routine "DGEEV". More...
 
void _lu_back_substitute_lapack (const DenseVector< T > &b, DenseVector< T > &x)
 Companion function to _lu_decompose_lapack(). More...
 
void _matvec_blas (T alpha, T beta, DenseVector< T > &dest, const DenseVector< T > &arg, bool trans=false) const
 Uses the BLAS GEMV function (through PETSc) to compute. More...
 

Private Attributes

std::vector< T > _val
 The actual data values, stored as a 1D array. More...
 
DecompositionType _decomposition_type
 This flag keeps track of which type of decomposition has been performed on the matrix. More...
 
std::vector< pivot_index_t_pivots
 

Detailed Description

template<typename T>
class libMesh::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. All overridden virtual functions are documented in dense_matrix_base.h.

Author
Benjamin S. Kirk
Date
2002

A matrix object used for finite element assembly and numerics.

Definition at line 73 of file dof_map.h.

Member Typedef Documentation

◆ pivot_index_t [1/2]

template<typename T>
typedef PetscBLASInt libMesh::DenseMatrix< T >::pivot_index_t
private

Array 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 698 of file dense_matrix.h.

◆ pivot_index_t [2/2]

template<typename T>
typedef int libMesh::DenseMatrix< T >::pivot_index_t
private

Definition at line 700 of file dense_matrix.h.

Member Enumeration Documentation

◆ _BLAS_Multiply_Flag

template<typename T>
enum libMesh::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 618 of file dense_matrix.h.

618  {
619  LEFT_MULTIPLY = 0,
623  };

◆ DecompositionType

template<typename T>
enum libMesh::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 606 of file dense_matrix.h.

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

Constructor & Destructor Documentation

◆ DenseMatrix() [1/3]

template<typename T >
libMesh::DenseMatrix< T >::DenseMatrix ( const unsigned int  new_m = 0,
const unsigned int  new_n = 0 
)
inline

Constructor.

Creates a dense matrix of dimension m by n.

Definition at line 774 of file dense_matrix.h.

775  :
776  DenseMatrixBase<T>(new_m,new_n),
777 #if defined(LIBMESH_HAVE_PETSC) && defined(LIBMESH_USE_REAL_NUMBERS) && defined(LIBMESH_DEFAULT_DOUBLE_PRECISION)
778  use_blas_lapack(true),
779 #else
780  use_blas_lapack(false),
781 #endif
782  _val(),
784 {
785  this->resize(new_m,new_n);
786 }

◆ DenseMatrix() [2/3]

template<typename T>
libMesh::DenseMatrix< T >::DenseMatrix ( DenseMatrix< T > &&  )
default

The 5 special functions can be defaulted for this class, as it does not manage any memory itself.

◆ DenseMatrix() [3/3]

template<typename T>
libMesh::DenseMatrix< T >::DenseMatrix ( const DenseMatrix< T > &  )
default

◆ ~DenseMatrix()

template<typename T>
virtual libMesh::DenseMatrix< T >::~DenseMatrix ( )
virtualdefault

Member Function Documentation

◆ _cholesky_back_substitute()

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

Solves the equation Ax=b for the unknown value x and rhs b based on the Cholesky factorization of A.

Note
This method may be used when A is real-valued and b and x are complex-valued.

Definition at line 1025 of file dense_matrix_impl.h.

1027 {
1028  // Shorthand notation for number of rows and columns.
1029  const unsigned int
1030  n_rows = this->m(),
1031  n_cols = this->n();
1032 
1033  // Just to be really sure...
1034  libmesh_assert_equal_to (n_rows, n_cols);
1035 
1036  // A convenient reference to *this
1037  const DenseMatrix<T> & A = *this;
1038 
1039  // Now compute the solution to Ax =b using the factorization.
1040  x.resize(n_rows);
1041 
1042  // Solve for Ly=b
1043  for (unsigned int i=0; i<n_cols; ++i)
1044  {
1045  T2 temp = b(i);
1046 
1047  for (unsigned int k=0; k<i; ++k)
1048  temp -= A(i,k)*x(k);
1049 
1050  x(i) = temp / A(i,i);
1051  }
1052 
1053  // Solve for L^T x = y
1054  for (unsigned int i=0; i<n_cols; ++i)
1055  {
1056  const unsigned int ib = (n_cols-1)-i;
1057 
1058  for (unsigned int k=(ib+1); k<n_cols; ++k)
1059  x(ib) -= A(k,ib) * x(k);
1060 
1061  x(ib) /= A(ib,ib);
1062  }
1063 }

◆ _cholesky_decompose()

template<typename T >
void libMesh::DenseMatrix< T >::_cholesky_decompose ( )
private

Decomposes a symmetric positive definite matrix into a product of two lower triangular matrices according to A = LL^T.

Note
This program generates an error if the matrix is not SPD.

Definition at line 979 of file dense_matrix_impl.h.

980 {
981  // If we called this function, there better not be any
982  // previous decomposition of the matrix.
983  libmesh_assert_equal_to (this->_decomposition_type, NONE);
984 
985  // Shorthand notation for number of rows and columns.
986  const unsigned int
987  n_rows = this->m(),
988  n_cols = this->n();
989 
990  // Just to be really sure...
991  libmesh_assert_equal_to (n_rows, n_cols);
992 
993  // A convenient reference to *this
994  DenseMatrix<T> & A = *this;
995 
996  for (unsigned int i=0; i<n_rows; ++i)
997  {
998  for (unsigned int j=i; j<n_cols; ++j)
999  {
1000  for (unsigned int k=0; k<i; ++k)
1001  A(i,j) -= A(i,k) * A(j,k);
1002 
1003  if (i == j)
1004  {
1005 #ifndef LIBMESH_USE_COMPLEX_NUMBERS
1006  if (A(i,j) <= 0.0)
1007  libmesh_error_msg("Error! Can only use Cholesky decomposition with symmetric positive definite matrices.");
1008 #endif
1009 
1010  A(i,i) = std::sqrt(A(i,j));
1011  }
1012  else
1013  A(j,i) = A(i,j) / A(i,i);
1014  }
1015  }
1016 
1017  // Set the flag for CHOLESKY decomposition
1018  this->_decomposition_type = CHOLESKY;
1019 }

◆ _evd_lapack()

template<typename T>
template void libMesh::DenseMatrix< T >::_evd_lapack ( DenseVector< T > &  lambda_real,
DenseVector< T > &  lambda_imag,
DenseMatrix< T > *  VL = nullptr,
DenseMatrix< T > *  VR = nullptr 
)
private

Computes the eigenvalues of the matrix using the Lapack routine "DGEEV".

If VR and/or VL are not nullptr, then the matrix of right and/or left eigenvectors is also computed and returned by this function.

[ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 711 of file dense_matrix_blas_lapack.C.

715 {
716  // This algorithm only works for square matrices, so verify this up front.
717  if (this->m() != this->n())
718  libmesh_error_msg("Can only compute eigen-decompositions for square matrices.");
719 
720  // If the user requests left or right eigenvectors, we have to make
721  // sure and pass the transpose of this matrix to Lapack, otherwise
722  // it will compute the inverse transpose of what we are
723  // after... since we know the matrix is square, we can just swap
724  // entries in place. If the user does not request eigenvectors, we
725  // can skip this extra step, since the eigenvalues for A and A^T are
726  // the same.
727  if (VL || VR)
728  {
729  for (auto i : IntRange<int>(0, this->_m))
730  for (auto j : IntRange<int>(0, i))
731  std::swap((*this)(i,j), (*this)(j,i));
732  }
733 
734  // The calling sequence for dgeev is:
735  // DGEEV (character JOBVL,
736  // character JOBVR,
737  // integer N,
738  // double precision, dimension( lda, * ) A,
739  // integer LDA,
740  // double precision, dimension( * ) WR,
741  // double precision, dimension( * ) WI,
742  // double precision, dimension( ldvl, * ) VL,
743  // integer LDVL,
744  // double precision, dimension( ldvr, * ) VR,
745  // integer LDVR,
746  // double precision, dimension( * ) WORK,
747  // integer LWORK,
748  // integer INFO)
749 
750  // JOBVL (input)
751  // = 'N': left eigenvectors of A are not computed;
752  // = 'V': left eigenvectors of A are computed.
753  char JOBVL = VL ? 'V' : 'N';
754 
755  // JOBVR (input)
756  // = 'N': right eigenvectors of A are not computed;
757  // = 'V': right eigenvectors of A are computed.
758  char JOBVR = VR ? 'V' : 'N';
759 
760  // N (input)
761  // The number of rows/cols of the matrix A. N >= 0.
762  PetscBLASInt N = this->m();
763 
764  // A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
765  // On entry, the N-by-N matrix A.
766  // On exit, A has been overwritten.
767 
768  // LDA (input)
769  // The leading dimension of the array A. LDA >= max(1,N).
770  PetscBLASInt LDA = N;
771 
772  // WR (output) double precision array, dimension (N)
773  // WI (output) double precision array, dimension (N)
774  // WR and WI contain the real and imaginary parts,
775  // respectively, of the computed eigenvalues. Complex
776  // conjugate pairs of eigenvalues appear consecutively
777  // with the eigenvalue having the positive imaginary part
778  // first.
779  lambda_real.resize(N);
780  lambda_imag.resize(N);
781 
782  // VL (output) double precision array, dimension (LDVL,N)
783  // If JOBVL = 'V', the left eigenvectors u(j) are stored one
784  // after another in the columns of VL, in the same order
785  // as their eigenvalues.
786  // If JOBVL = 'N', VL is not referenced.
787  // If the j-th eigenvalue is real, then u(j) = VL(:,j),
788  // the j-th column of VL.
789  // If the j-th and (j+1)-st eigenvalues form a complex
790  // conjugate pair, then u(j) = VL(:,j) + i*VL(:,j+1) and
791  // u(j+1) = VL(:,j) - i*VL(:,j+1).
792  // Will be set below if needed.
793 
794  // LDVL (input)
795  // The leading dimension of the array VL. LDVL >= 1; if
796  // JOBVL = 'V', LDVL >= N.
797  PetscBLASInt LDVL = VL ? N : 1;
798 
799  // VR (output) DOUBLE PRECISION array, dimension (LDVR,N)
800  // If JOBVR = 'V', the right eigenvectors v(j) are stored one
801  // after another in the columns of VR, in the same order
802  // as their eigenvalues.
803  // If JOBVR = 'N', VR is not referenced.
804  // If the j-th eigenvalue is real, then v(j) = VR(:,j),
805  // the j-th column of VR.
806  // If the j-th and (j+1)-st eigenvalues form a complex
807  // conjugate pair, then v(j) = VR(:,j) + i*VR(:,j+1) and
808  // v(j+1) = VR(:,j) - i*VR(:,j+1).
809  // Will be set below if needed.
810 
811  // LDVR (input)
812  // The leading dimension of the array VR. LDVR >= 1; if
813  // JOBVR = 'V', LDVR >= N.
814  PetscBLASInt LDVR = VR ? N : 1;
815 
816  // WORK (workspace/output) double precision array, dimension (MAX(1,LWORK))
817  // On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
818  //
819  // LWORK (input)
820  // The dimension of the array WORK. LWORK >= max(1,3*N), and
821  // if JOBVL = 'V' or JOBVR = 'V', LWORK >= 4*N. For good
822  // performance, LWORK must generally be larger.
823  //
824  // If LWORK = -1, then a workspace query is assumed; the routine
825  // only calculates the optimal size of the WORK array, returns
826  // this value as the first entry of the WORK array, and no error
827  // message related to LWORK is issued by XERBLA.
828  PetscBLASInt LWORK = (VR || VL) ? 4*N : 3*N;
829  std::vector<T> WORK(LWORK);
830 
831  // INFO (output)
832  // = 0: successful exit
833  // < 0: if INFO = -i, the i-th argument had an illegal value.
834  // > 0: if INFO = i, the QR algorithm failed to compute all the
835  // eigenvalues, and no eigenvectors or condition numbers
836  // have been computed; elements 1:ILO-1 and i+1:N of WR
837  // and WI contain eigenvalues which have converged.
838  PetscBLASInt INFO = 0;
839 
840  // Get references to raw data
841  std::vector<T> & lambda_real_val = lambda_real.get_values();
842  std::vector<T> & lambda_imag_val = lambda_imag.get_values();
843 
844  // Set up eigenvector storage if necessary.
845  T * VR_ptr = nullptr;
846  if (VR)
847  {
848  VR->resize(N, N);
849  VR_ptr = VR->get_values().data();
850  }
851 
852  T * VL_ptr = nullptr;
853  if (VL)
854  {
855  VL->resize(N, N);
856  VL_ptr = VL->get_values().data();
857  }
858 
859  // Ready to call the Lapack routine through PETSc's interface
860  LAPACKgeev_(&JOBVL,
861  &JOBVR,
862  &N,
863  pPS(_val.data()),
864  &LDA,
865  pPS(lambda_real_val.data()),
866  pPS(lambda_imag_val.data()),
867  pPS(VL_ptr),
868  &LDVL,
869  pPS(VR_ptr),
870  &LDVR,
871  pPS(WORK.data()),
872  &LWORK,
873  &INFO);
874 
875  // Check return value for errors
876  if (INFO != 0)
877  libmesh_error_msg("INFO=" << INFO << ", Error during Lapack eigenvalue calculation!");
878 
879  // If the user requested either right or left eigenvectors, LAPACK
880  // has now computed the transpose of the desired matrix, i.e. V^T
881  // instead of V. We could leave this up to user code to handle, but
882  // rather than risking getting very unexpected results, we'll just
883  // transpose it in place before handing it back.
884  if (VR)
885  {
886  for (auto i : IntRange<int>(0, N))
887  for (auto j : IntRange<int>(0, i))
888  std::swap((*VR)(i,j), (*VR)(j,i));
889  }
890 
891  if (VL)
892  {
893  for (auto i : IntRange<int>(0, N))
894  for (auto j : IntRange<int>(0, i))
895  std::swap((*VL)(i,j), (*VL)(j,i));
896  }
897 }

◆ _lu_back_substitute()

template<typename T>
void libMesh::DenseMatrix< T >::_lu_back_substitute ( const DenseVector< T > &  b,
DenseVector< T > &  x 
) const
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 684 of file dense_matrix_impl.h.

686 {
687  const unsigned int
688  n_cols = this->n();
689 
690  libmesh_assert_equal_to (this->m(), n_cols);
691  libmesh_assert_equal_to (this->m(), b.size());
692 
693  x.resize (n_cols);
694 
695  // A convenient reference to *this
696  const DenseMatrix<T> & A = *this;
697 
698  // Temporary vector storage. We use this instead of
699  // modifying the RHS.
700  DenseVector<T> z = b;
701 
702  // Lower-triangular "top to bottom" solve step, taking into account pivots
703  for (unsigned int i=0; i<n_cols; ++i)
704  {
705  // Swap
706  if (_pivots[i] != static_cast<pivot_index_t>(i))
707  std::swap( z(i), z(_pivots[i]) );
708 
709  x(i) = z(i);
710 
711  for (unsigned int j=0; j<i; ++j)
712  x(i) -= A(i,j)*x(j);
713 
714  x(i) /= A(i,i);
715  }
716 
717  // Upper-triangular "bottom to top" solve step
718  const unsigned int last_row = n_cols-1;
719 
720  for (int i=last_row; i>=0; --i)
721  {
722  for (int j=i+1; j<static_cast<int>(n_cols); ++j)
723  x(i) -= A(i,j)*x(j);
724  }
725 }

◆ _lu_back_substitute_lapack()

template<typename T>
template void libMesh::DenseMatrix< T >::_lu_back_substitute_lapack ( const DenseVector< T > &  b,
DenseVector< T > &  x 
)
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 919 of file dense_matrix_blas_lapack.C.

921 {
922  // The calling sequence for getrs is:
923  // dgetrs(TRANS, N, NRHS, A, LDA, IPIV, B, LDB, INFO)
924 
925  // trans (input)
926  // 'n' for no transpose, 't' for transpose
927  char TRANS[] = "t";
928 
929  // N (input)
930  // The order of the matrix A. N >= 0.
931  PetscBLASInt N = this->m();
932 
933 
934  // NRHS (input)
935  // The number of right hand sides, i.e., the number of columns
936  // of the matrix B. NRHS >= 0.
937  PetscBLASInt NRHS = 1;
938 
939  // A (input) double precision array, dimension (LDA,N)
940  // The factors L and U from the factorization A = P*L*U
941  // as computed by dgetrf.
942 
943  // LDA (input)
944  // The leading dimension of the array A. LDA >= max(1,N).
945  PetscBLASInt LDA = N;
946 
947  // ipiv (input) int array, dimension (N)
948  // The pivot indices from DGETRF; for 1<=i<=N, row i of the
949  // matrix was interchanged with row IPIV(i).
950  // Here, we pass _pivots.data() which was computed in _lu_decompose_lapack
951 
952  // B (input/output) double precision array, dimension (LDB,NRHS)
953  // On entry, the right hand side matrix B.
954  // On exit, the solution matrix X.
955  // Here, we pass a copy of the rhs vector's data array in x, so that the
956  // passed right-hand side b is unmodified. I don't see a way around this
957  // copy if we want to maintain an unmodified rhs in LibMesh.
958  x = b;
959  std::vector<T> & x_vec = x.get_values();
960 
961  // We can avoid the copy if we don't care about overwriting the RHS: just
962  // pass b to the Lapack routine and then swap with x before exiting
963  // std::vector<T> & x_vec = b.get_values();
964 
965  // LDB (input)
966  // The leading dimension of the array B. LDB >= max(1,N).
967  PetscBLASInt LDB = N;
968 
969  // INFO (output)
970  // = 0: successful exit
971  // < 0: if INFO = -i, the i-th argument had an illegal value
972  PetscBLASInt INFO = 0;
973 
974  // Finally, ready to call the Lapack getrs function
975  LAPACKgetrs_(TRANS, &N, &NRHS, pPS(_val.data()), &LDA,
976  _pivots.data(), pPS(x_vec.data()), &LDB, &INFO);
977 
978  // Check return value for errors
979  if (INFO != 0)
980  libmesh_error_msg("INFO=" << INFO << ", Error during Lapack LU solve!");
981 
982  // Don't do this if you already made a copy of b above
983  // Swap b and x. The solution will then be in x, and whatever was originally
984  // in x, maybe garbage, maybe nothing, will be in b.
985  // FIXME: Rewrite the LU and Cholesky solves to just take one input, and overwrite
986  // the input. This *should* make user code simpler, as they don't have to create
987  // an extra vector just to pass it in to the solve function!
988  // b.swap(x);
989 }

◆ _lu_decompose()

template<typename T >
void libMesh::DenseMatrix< T >::_lu_decompose ( )
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 735 of file dense_matrix_impl.h.

736 {
737  // If this function was called, there better not be any
738  // previous decomposition of the matrix.
739  libmesh_assert_equal_to (this->_decomposition_type, NONE);
740 
741  // Get the matrix size and make sure it is square
742  const unsigned int
743  n_rows = this->m();
744 
745  // A convenient reference to *this
746  DenseMatrix<T> & A = *this;
747 
748  _pivots.resize(n_rows);
749 
750  for (unsigned int i=0; i<n_rows; ++i)
751  {
752  // Find the pivot row by searching down the i'th column
753  _pivots[i] = i;
754 
755  // std::abs(complex) must return a Real!
756  auto the_max = std::abs( A(i,i) );
757  for (unsigned int j=i+1; j<n_rows; ++j)
758  {
759  auto candidate_max = std::abs( A(j,i) );
760  if (the_max < candidate_max)
761  {
762  the_max = candidate_max;
763  _pivots[i] = j;
764  }
765  }
766 
767  // libMesh::out << "the_max=" << the_max << " found at row " << _pivots[i] << std::endl;
768 
769  // If the max was found in a different row, interchange rows.
770  // Here we interchange the *entire* row, in Gaussian elimination
771  // you would only interchange the subrows A(i,j) and A(p(i),j), for j>i
772  if (_pivots[i] != static_cast<pivot_index_t>(i))
773  {
774  for (unsigned int j=0; j<n_rows; ++j)
775  std::swap( A(i,j), A(_pivots[i], j) );
776  }
777 
778 
779  // If the max abs entry found is zero, the matrix is singular
780  if (A(i,i) == libMesh::zero)
781  libmesh_error_msg("Matrix A is singular!");
782 
783  // Scale upper triangle entries of row i by the diagonal entry
784  // Note: don't scale the diagonal entry itself!
785  const T diag_inv = 1. / A(i,i);
786  for (unsigned int j=i+1; j<n_rows; ++j)
787  A(i,j) *= diag_inv;
788 
789  // Update the remaining sub-matrix A[i+1:m][i+1:m]
790  // by subtracting off (the diagonal-scaled)
791  // upper-triangular part of row i, scaled by the
792  // i'th column entry of each row. In terms of
793  // row operations, this is:
794  // for each r > i
795  // SubRow(r) = SubRow(r) - A(r,i)*SubRow(i)
796  //
797  // If we were scaling the i'th column as well, like
798  // in Gaussian elimination, this would 'zero' the
799  // entry in the i'th column.
800  for (unsigned int row=i+1; row<n_rows; ++row)
801  for (unsigned int col=i+1; col<n_rows; ++col)
802  A(row,col) -= A(row,i) * A(i,col);
803 
804  } // end i loop
805 
806  // Set the flag for LU decomposition
807  this->_decomposition_type = LU;
808 }

◆ _lu_decompose_lapack()

template<typename T >
template void libMesh::DenseMatrix< T >::_lu_decompose_lapack ( )
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 210 of file dense_matrix_blas_lapack.C.

211 {
212  // If this function was called, there better not be any
213  // previous decomposition of the matrix.
214  libmesh_assert_equal_to (this->_decomposition_type, NONE);
215 
216  // The calling sequence for dgetrf is:
217  // dgetrf(M, N, A, lda, ipiv, info)
218 
219  // M (input)
220  // The number of rows of the matrix A. M >= 0.
221  // In C/C++, pass the number of *cols* of A
222  PetscBLASInt M = this->n();
223 
224  // N (input)
225  // The number of columns of the matrix A. N >= 0.
226  // In C/C++, pass the number of *rows* of A
227  PetscBLASInt N = this->m();
228 
229  // A (input/output) double precision array, dimension (LDA,N)
230  // On entry, the M-by-N matrix to be factored.
231  // On exit, the factors L and U from the factorization
232  // A = P*L*U; the unit diagonal elements of L are not stored.
233 
234  // LDA (input)
235  // The leading dimension of the array A. LDA >= max(1,M).
236  PetscBLASInt LDA = M;
237 
238  // ipiv (output) integer array, dimension (min(m,n))
239  // The pivot indices; for 1 <= i <= min(m,n), row i of the
240  // matrix was interchanged with row IPIV(i).
241  // Here, we pass _pivots.data(), a private class member used to store pivots
242  this->_pivots.resize( std::min(M,N) );
243 
244  // info (output)
245  // = 0: successful exit
246  // < 0: if INFO = -i, the i-th argument had an illegal value
247  // > 0: if INFO = i, U(i,i) is exactly zero. The factorization
248  // has been completed, but the factor U is exactly
249  // singular, and division by zero will occur if it is used
250  // to solve a system of equations.
251  PetscBLASInt INFO = 0;
252 
253  // Ready to call the actual factorization routine through PETSc's interface
254  LAPACKgetrf_(&M, &N, pPS(this->_val.data()), &LDA, _pivots.data(),
255  &INFO);
256 
257  // Check return value for errors
258  if (INFO != 0)
259  libmesh_error_msg("INFO=" << INFO << ", Error during Lapack LU factorization!");
260 
261  // Set the flag for LU decomposition
263 }

◆ _matvec_blas()

template<typename T>
template void libMesh::DenseMatrix< T >::_matvec_blas ( alpha,
beta,
DenseVector< T > &  dest,
const DenseVector< T > &  arg,
bool  trans = false 
) const
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. If trans is true, the transpose matvec is computed instead. By default, trans==false.

[ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 1009 of file dense_matrix_blas_lapack.C.

1014 {
1015  // Ensure that dest and arg sizes are compatible
1016  if (!trans)
1017  {
1018  // dest ~ A * arg
1019  // (mx1) (mxn) * (nx1)
1020  if ((dest.size() != this->m()) || (arg.size() != this->n()))
1021  libmesh_error_msg("Improper input argument sizes!");
1022  }
1023 
1024  else // trans == true
1025  {
1026  // Ensure that dest and arg are proper size
1027  // dest ~ A^T * arg
1028  // (nx1) (nxm) * (mx1)
1029  if ((dest.size() != this->n()) || (arg.size() != this->m()))
1030  libmesh_error_msg("Improper input argument sizes!");
1031  }
1032 
1033  // Calling sequence for dgemv:
1034  //
1035  // dgemv(TRANS,M,N,ALPHA,A,LDA,X,INCX,BETA,Y,INCY)
1036 
1037  // TRANS (input)
1038  // 't' for transpose, 'n' for non-transpose multiply
1039  // We store everything in row-major order, so pass the transpose flag for
1040  // non-transposed matvecs and the 'n' flag for transposed matvecs
1041  char TRANS[] = "t";
1042  if (trans)
1043  TRANS[0] = 'n';
1044 
1045  // M (input)
1046  // On entry, M specifies the number of rows of the matrix A.
1047  // In C/C++, pass the number of *cols* of A
1048  PetscBLASInt M = this->n();
1049 
1050  // N (input)
1051  // On entry, N specifies the number of columns of the matrix A.
1052  // In C/C++, pass the number of *rows* of A
1053  PetscBLASInt N = this->m();
1054 
1055  // ALPHA (input)
1056  // The scalar constant passed to this function
1057 
1058  // A (input) double precision array of DIMENSION ( LDA, n ).
1059  // Before entry, the leading m by n part of the array A must
1060  // contain the matrix of coefficients.
1061  // The matrix, *this. Note that _matvec_blas is called from
1062  // a const function, vector_mult(), and so we have made this function const
1063  // as well. Since BLAS knows nothing about const, we have to cast it away
1064  // now.
1065  DenseMatrix<T> & a_ref = const_cast<DenseMatrix<T> &> ( *this );
1066  std::vector<T> & a = a_ref.get_values();
1067 
1068  // LDA (input)
1069  // On entry, LDA specifies the first dimension of A as declared
1070  // in the calling (sub) program. LDA must be at least
1071  // max( 1, m ).
1072  PetscBLASInt LDA = M;
1073 
1074  // X (input) double precision array of DIMENSION at least
1075  // ( 1 + ( n - 1 )*abs( INCX ) ) when TRANS = 'N' or 'n'
1076  // and at least
1077  // ( 1 + ( m - 1 )*abs( INCX ) ) otherwise.
1078  // Before entry, the incremented array X must contain the
1079  // vector x.
1080  // Here, we must cast away the const-ness of "arg" since BLAS knows
1081  // nothing about const
1082  DenseVector<T> & x_ref = const_cast<DenseVector<T> &> ( arg );
1083  std::vector<T> & x = x_ref.get_values();
1084 
1085  // INCX (input)
1086  // On entry, INCX specifies the increment for the elements of
1087  // X. INCX must not be zero.
1088  PetscBLASInt INCX = 1;
1089 
1090  // BETA (input)
1091  // On entry, BETA specifies the scalar beta. When BETA is
1092  // supplied as zero then Y need not be set on input.
1093  // The second scalar constant passed to this function
1094 
1095  // Y (input) double precision array of DIMENSION at least
1096  // ( 1 + ( m - 1 )*abs( INCY ) ) when TRANS = 'N' or 'n'
1097  // and at least
1098  // ( 1 + ( n - 1 )*abs( INCY ) ) otherwise.
1099  // Before entry with BETA non-zero, the incremented array Y
1100  // must contain the vector y. On exit, Y is overwritten by the
1101  // updated vector y.
1102  // The input vector "dest"
1103  std::vector<T> & y = dest.get_values();
1104 
1105  // INCY (input)
1106  // On entry, INCY specifies the increment for the elements of
1107  // Y. INCY must not be zero.
1108  PetscBLASInt INCY = 1;
1109 
1110  // Finally, ready to call the BLAS function
1111  BLASgemv_(TRANS, &M, &N, pPS(&alpha), pPS(a.data()), &LDA,
1112  pPS(x.data()), &INCX, pPS(&beta), pPS(y.data()), &INCY);
1113 }

◆ _multiply_blas()

template<typename T>
template void libMesh::DenseMatrix< T >::_multiply_blas ( const DenseMatrixBase< T > &  other,
_BLAS_Multiply_Flag  flag 
)
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_transpose() routines. [ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 37 of file dense_matrix_blas_lapack.C.

39 {
40  int result_size = 0;
41 
42  // For each case, determine the size of the final result make sure
43  // that the inner dimensions match
44  switch (flag)
45  {
46  case LEFT_MULTIPLY:
47  {
48  result_size = other.m() * this->n();
49  if (other.n() == this->m())
50  break;
51  }
52  libmesh_fallthrough();
53  case RIGHT_MULTIPLY:
54  {
55  result_size = other.n() * this->m();
56  if (other.m() == this->n())
57  break;
58  }
59  libmesh_fallthrough();
61  {
62  result_size = other.n() * this->n();
63  if (other.m() == this->m())
64  break;
65  }
66  libmesh_fallthrough();
68  {
69  result_size = other.m() * this->m();
70  if (other.n() == this->n())
71  break;
72  }
73  libmesh_fallthrough();
74  default:
75  libmesh_error_msg("Unknown flag selected or matrices are incompatible for multiplication.");
76  }
77 
78  // For this to work, the passed arg. must actually be a DenseMatrix<T>
79  const DenseMatrix<T> * const_that = cast_ptr<const DenseMatrix<T> *>(&other);
80 
81  // Also, although 'that' is logically const in this BLAS routine,
82  // the PETSc BLAS interface does not specify that any of the inputs are
83  // const. To use it, I must cast away const-ness.
84  DenseMatrix<T> * that = const_cast<DenseMatrix<T> *> (const_that);
85 
86  // Initialize A, B pointers for LEFT_MULTIPLY* cases
87  DenseMatrix<T> * A = this;
88  DenseMatrix<T> * B = that;
89 
90  // For RIGHT_MULTIPLY* cases, swap the meaning of A and B.
91  // Here is a full table of combinations we can pass to BLASgemm, and what the answer is when finished:
92  // pass A B -> (Fortran) -> A^T B^T -> (C++) -> (A^T B^T)^T -> (identity) -> B A "lt multiply"
93  // pass B A -> (Fortran) -> B^T A^T -> (C++) -> (B^T A^T)^T -> (identity) -> A B "rt multiply"
94  // pass A B^T -> (Fortran) -> A^T B -> (C++) -> (A^T B)^T -> (identity) -> B^T A "lt multiply t"
95  // pass B^T A -> (Fortran) -> B A^T -> (C++) -> (B A^T)^T -> (identity) -> A B^T "rt multiply t"
96  if (flag==RIGHT_MULTIPLY || flag==RIGHT_MULTIPLY_TRANSPOSE)
97  std::swap(A,B);
98 
99  // transa, transb values to pass to blas
100  char
101  transa[] = "n",
102  transb[] = "n";
103 
104  // Integer values to pass to BLAS:
105  //
106  // M
107  // In Fortran, the number of rows of op(A),
108  // In the BLAS documentation, typically known as 'M'.
109  //
110  // In C/C++, we set:
111  // M = n_cols(A) if (transa='n')
112  // n_rows(A) if (transa='t')
113  PetscBLASInt M = static_cast<PetscBLASInt>( A->n() );
114 
115  // N
116  // In Fortran, the number of cols of op(B), and also the number of cols of C.
117  // In the BLAS documentation, typically known as 'N'.
118  //
119  // In C/C++, we set:
120  // N = n_rows(B) if (transb='n')
121  // n_cols(B) if (transb='t')
122  PetscBLASInt N = static_cast<PetscBLASInt>( B->m() );
123 
124  // K
125  // In Fortran, the number of cols of op(A), and also
126  // the number of rows of op(B). In the BLAS documentation,
127  // typically known as 'K'.
128  //
129  // In C/C++, we set:
130  // K = n_rows(A) if (transa='n')
131  // n_cols(A) if (transa='t')
132  PetscBLASInt K = static_cast<PetscBLASInt>( A->m() );
133 
134  // LDA (leading dimension of A). In our cases,
135  // LDA is always the number of columns of A.
136  PetscBLASInt LDA = static_cast<PetscBLASInt>( A->n() );
137 
138  // LDB (leading dimension of B). In our cases,
139  // LDB is always the number of columns of B.
140  PetscBLASInt LDB = static_cast<PetscBLASInt>( B->n() );
141 
142  if (flag == LEFT_MULTIPLY_TRANSPOSE)
143  {
144  transb[0] = 't';
145  N = static_cast<PetscBLASInt>( B->n() );
146  }
147 
148  else if (flag == RIGHT_MULTIPLY_TRANSPOSE)
149  {
150  transa[0] = 't';
151  std::swap(M,K);
152  }
153 
154  // LDC (leading dimension of C). LDC is the
155  // number of columns in the solution matrix.
156  PetscBLASInt LDC = M;
157 
158  // Scalar values to pass to BLAS
159  //
160  // scalar multiplying the whole product AB
161  T alpha = 1.;
162 
163  // scalar multiplying C, which is the original matrix.
164  T beta = 0.;
165 
166  // Storage for the result
167  std::vector<T> result (result_size);
168 
169  // Finally ready to call the BLAS
170  BLASgemm_(transa, transb, &M, &N, &K, pPS(&alpha),
171  pPS(A->get_values().data()), &LDA,
172  pPS(B->get_values().data()), &LDB, pPS(&beta),
173  pPS(result.data()), &LDC);
174 
175  // Update the relevant dimension for this matrix.
176  switch (flag)
177  {
178  case LEFT_MULTIPLY: { this->_m = other.m(); break; }
179  case RIGHT_MULTIPLY: { this->_n = other.n(); break; }
180  case LEFT_MULTIPLY_TRANSPOSE: { this->_m = other.n(); break; }
181  case RIGHT_MULTIPLY_TRANSPOSE: { this->_n = other.m(); break; }
182  default:
183  libmesh_error_msg("Unknown flag selected.");
184  }
185 
186  // Swap my data vector with the result
187  this->_val.swap(result);
188 }

◆ _svd_helper()

template<typename T >
template void libMesh::DenseMatrix< T >::_svd_helper ( char  JOBU,
char  JOBVT,
std::vector< Real > &  sigma_val,
std::vector< Number > &  U_val,
std::vector< Number > &  VT_val 
)
private

Helper function that actually performs the SVD.

[ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 385 of file dense_matrix_blas_lapack.C.

390 {
391 
392  // M (input)
393  // The number of rows of the matrix A. M >= 0.
394  // In C/C++, pass the number of *cols* of A
395  PetscBLASInt M = this->n();
396 
397  // N (input)
398  // The number of columns of the matrix A. N >= 0.
399  // In C/C++, pass the number of *rows* of A
400  PetscBLASInt N = this->m();
401 
402  PetscBLASInt min_MN = (M < N) ? M : N;
403  PetscBLASInt max_MN = (M > N) ? M : N;
404 
405  // A (input/output) DOUBLE PRECISION array, dimension (LDA,N)
406  // On entry, the M-by-N matrix A.
407  // On exit,
408  // if JOBU = 'O', A is overwritten with the first min(m,n)
409  // columns of U (the left singular vectors,
410  // stored columnwise);
411  // if JOBVT = 'O', A is overwritten with the first min(m,n)
412  // rows of V**T (the right singular vectors,
413  // stored rowwise);
414  // if JOBU != 'O' and JOBVT != 'O', the contents of A are destroyed.
415 
416  // LDA (input)
417  // The leading dimension of the array A. LDA >= max(1,M).
418  PetscBLASInt LDA = M;
419 
420  // S (output) DOUBLE PRECISION array, dimension (min(M,N))
421  // The singular values of A, sorted so that S(i) >= S(i+1).
422  sigma_val.resize( min_MN );
423 
424  // LDU (input)
425  // The leading dimension of the array U. LDU >= 1; if
426  // JOBU = 'S' or 'A', LDU >= M.
427  PetscBLASInt LDU = M;
428 
429  // U (output) DOUBLE PRECISION array, dimension (LDU,UCOL)
430  // (LDU,M) if JOBU = 'A' or (LDU,min(M,N)) if JOBU = 'S'.
431  // If JOBU = 'A', U contains the M-by-M orthogonal matrix U;
432  // if JOBU = 'S', U contains the first min(m,n) columns of U
433  // (the left singular vectors, stored columnwise);
434  // if JOBU = 'N' or 'O', U is not referenced.
435  if (JOBU == 'S')
436  U_val.resize( LDU*min_MN );
437  else
438  U_val.resize( LDU*M );
439 
440  // LDVT (input)
441  // The leading dimension of the array VT. LDVT >= 1; if
442  // JOBVT = 'A', LDVT >= N; if JOBVT = 'S', LDVT >= min(M,N).
443  PetscBLASInt LDVT = N;
444  if (JOBVT == 'S')
445  LDVT = min_MN;
446 
447  // VT (output) DOUBLE PRECISION array, dimension (LDVT,N)
448  // If JOBVT = 'A', VT contains the N-by-N orthogonal matrix
449  // V**T;
450  // if JOBVT = 'S', VT contains the first min(m,n) rows of
451  // V**T (the right singular vectors, stored rowwise);
452  // if JOBVT = 'N' or 'O', VT is not referenced.
453  VT_val.resize( LDVT*N );
454 
455  // LWORK (input)
456  // The dimension of the array WORK.
457  // LWORK >= MAX(1,3*MIN(M,N)+MAX(M,N),5*MIN(M,N)).
458  // For good performance, LWORK should generally be larger.
459  //
460  // If LWORK = -1, then a workspace query is assumed; the routine
461  // only calculates the optimal size of the WORK array, returns
462  // this value as the first entry of the WORK array, and no error
463  // message related to LWORK is issued by XERBLA.
464  PetscBLASInt larger = (3*min_MN+max_MN > 5*min_MN) ? 3*min_MN+max_MN : 5*min_MN;
465  PetscBLASInt LWORK = (larger > 1) ? larger : 1;
466 
467 
468  // WORK (workspace/output) DOUBLE PRECISION array, dimension (MAX(1,LWORK))
469  // On exit, if INFO = 0, WORK(1) returns the optimal LWORK;
470  // if INFO > 0, WORK(2:MIN(M,N)) contains the unconverged
471  // superdiagonal elements of an upper bidiagonal matrix B
472  // whose diagonal is in S (not necessarily sorted). B
473  // satisfies A = U * B * VT, so it has the same singular values
474  // as A, and singular vectors related by U and VT.
475  std::vector<Number> WORK( LWORK );
476 
477  // INFO (output)
478  // = 0: successful exit.
479  // < 0: if INFO = -i, the i-th argument had an illegal value.
480  // > 0: if DBDSQR did not converge, INFO specifies how many
481  // superdiagonals of an intermediate bidiagonal form B
482  // did not converge to zero. See the description of WORK
483  // above for details.
484  PetscBLASInt INFO = 0;
485 
486  // Ready to call the actual factorization routine through PETSc's interface.
487 #ifdef LIBMESH_USE_REAL_NUMBERS
488  // Note that the call to LAPACKgesvd_ may modify _val
489  LAPACKgesvd_(&JOBU, &JOBVT, &M, &N, pPS(_val.data()), &LDA,
490  pPS(sigma_val.data()), pPS(U_val.data()), &LDU,
491  pPS(VT_val.data()), &LDVT, pPS(WORK.data()), &LWORK,
492  &INFO);
493 #else
494  // When we have LIBMESH_USE_COMPLEX_NUMBERS then we must pass an array of Complex
495  // numbers to LAPACKgesvd_, but _val may contain Reals so we copy to Number below to
496  // handle both the real-valued and complex-valued cases.
497  std::vector<Number> val_copy(_val.size());
498  for (auto i : IntRange<int>(0, _val.size()))
499  val_copy[i] = _val[i];
500 
501  std::vector<Real> RWORK(5 * min_MN);
502  LAPACKgesvd_(&JOBU, &JOBVT, &M, &N, val_copy.data(), &LDA, sigma_val.data(), U_val.data(),
503  &LDU, VT_val.data(), &LDVT, WORK.data(), &LWORK, RWORK.data(), &INFO);
504 #endif
505 
506  // Check return value for errors
507  if (INFO != 0)
508  libmesh_error_msg("INFO=" << INFO << ", Error during Lapack SVD calculation!");
509 }

◆ _svd_lapack() [1/2]

template<typename T >
template void libMesh::DenseMatrix< T >::_svd_lapack ( DenseVector< Real > &  sigma)
private

Computes an SVD of the matrix using the Lapack routine "getsvd".

[ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 278 of file dense_matrix_blas_lapack.C.

279 {
280  // The calling sequence for dgetrf is:
281  // DGESVD( JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO )
282 
283  // JOBU (input)
284  // Specifies options for computing all or part of the matrix U:
285  // = 'A': all M columns of U are returned in array U:
286  // = 'S': the first min(m,n) columns of U (the left singular
287  // vectors) are returned in the array U;
288  // = 'O': the first min(m,n) columns of U (the left singular
289  // vectors) are overwritten on the array A;
290  // = 'N': no columns of U (no left singular vectors) are
291  // computed.
292  char JOBU = 'N';
293 
294  // JOBVT (input)
295  // Specifies options for computing all or part of the matrix
296  // V**T:
297  // = 'A': all N rows of V**T are returned in the array VT;
298  // = 'S': the first min(m,n) rows of V**T (the right singular
299  // vectors) are returned in the array VT;
300  // = 'O': the first min(m,n) rows of V**T (the right singular
301  // vectors) are overwritten on the array A;
302  // = 'N': no rows of V**T (no right singular vectors) are
303  // computed.
304  char JOBVT = 'N';
305 
306  std::vector<Real> sigma_val;
307  std::vector<Number> U_val;
308  std::vector<Number> VT_val;
309 
310  _svd_helper(JOBU, JOBVT, sigma_val, U_val, VT_val);
311 
312  // Copy the singular values into sigma, ignore U_val and VT_val
313  sigma.resize(cast_int<unsigned int>(sigma_val.size()));
314  for (auto i : IntRange<int>(0, sigma.size()))
315  sigma(i) = sigma_val[i];
316 }

◆ _svd_lapack() [2/2]

template<typename T >
template void libMesh::DenseMatrix< T >::_svd_lapack ( DenseVector< Real > &  sigma,
DenseMatrix< Number > &  U,
DenseMatrix< Number > &  VT 
)
private

Computes a "reduced" SVD of the matrix using the Lapack routine "getsvd".

[ Implementation in dense_matrix_blas_lapack.C ]

Definition at line 319 of file dense_matrix_blas_lapack.C.

322 {
323  // The calling sequence for dgetrf is:
324  // DGESVD( JOBU, JOBVT, M, N, A, LDA, S, U, LDU, VT, LDVT, WORK, LWORK, INFO )
325 
326  // JOBU (input)
327  // Specifies options for computing all or part of the matrix U:
328  // = 'A': all M columns of U are returned in array U:
329  // = 'S': the first min(m,n) columns of U (the left singular
330  // vectors) are returned in the array U;
331  // = 'O': the first min(m,n) columns of U (the left singular
332  // vectors) are overwritten on the array A;
333  // = 'N': no columns of U (no left singular vectors) are
334  // computed.
335  char JOBU = 'S';
336 
337  // JOBVT (input)
338  // Specifies options for computing all or part of the matrix
339  // V**T:
340  // = 'A': all N rows of V**T are returned in the array VT;
341  // = 'S': the first min(m,n) rows of V**T (the right singular
342  // vectors) are returned in the array VT;
343  // = 'O': the first min(m,n) rows of V**T (the right singular
344  // vectors) are overwritten on the array A;
345  // = 'N': no rows of V**T (no right singular vectors) are
346  // computed.
347  char JOBVT = 'S';
348 
349  // Note: Lapack is going to compute the singular values of A^T. If
350  // A=U * S * V^T, then A^T = V * S * U^T, which means that the
351  // values returned in the "U_val" array actually correspond to the
352  // entries of the V matrix, and the values returned in the VT_val
353  // array actually correspond to the entries of U^T. Therefore, we
354  // pass VT in the place of U and U in the place of VT below!
355  std::vector<Real> sigma_val;
356  int M = this->n();
357  int N = this->m();
358  int min_MN = (M < N) ? M : N;
359 
360  // Size user-provided storage appropriately. Inside svd_helper:
361  // U_val is sized to (M x min_MN)
362  // VT_val is sized to (min_MN x N)
363  // So, we set up U to have the shape of "VT_val^T", and VT to
364  // have the shape of "U_val^T".
365  //
366  // Finally, since the results are stored in column-major order by
367  // Lapack, but we actually want the transpose of what Lapack
368  // returns, this means (conveniently) that we don't even have to
369  // copy anything after the call to _svd_helper, it should already be
370  // in the correct order!
371  U.resize(N, min_MN);
372  VT.resize(min_MN, M);
373 
374  _svd_helper(JOBU, JOBVT, sigma_val, VT.get_values(), U.get_values());
375 
376  // Copy the singular values into sigma.
377  sigma.resize(cast_int<unsigned int>(sigma_val.size()));
378  for (auto i : IntRange<int>(0, sigma.size()))
379  sigma(i) = sigma_val[i];
380 }

◆ _svd_solve_lapack()

template<typename T>
template void libMesh::DenseMatrix< T >::_svd_solve_lapack ( const DenseVector< T > &  rhs,
DenseVector< T > &  x,
Real  rcond 
) const
private

Called by svd_solve(rhs).

Definition at line 532 of file dense_matrix_blas_lapack.C.

535 {
536  // Since BLAS is expecting column-major storage, we first need to
537  // make a transposed copy of *this, then pass it to the gelss
538  // routine instead of the original. This extra copy is kind of a
539  // bummer, it might be better if we could use the full SVD to
540  // compute the least-squares solution instead... Note that it isn't
541  // completely terrible either, since A_trans gets overwritten by
542  // Lapack, and we usually would end up making a copy of A outside
543  // the function call anyway.
544  DenseMatrix<T> A_trans;
545  this->get_transpose(A_trans);
546 
547  // M
548  // The number of rows of the input matrix. M >= 0.
549  // This is actually the number of *columns* of A_trans.
550  PetscBLASInt M = A_trans.n();
551 
552  // N
553  // The number of columns of the matrix A. N >= 0.
554  // This is actually the number of *rows* of A_trans.
555  PetscBLASInt N = A_trans.m();
556 
557  // We'll use the min and max of (M,N) several times below.
558  PetscBLASInt max_MN = std::max(M,N);
559  PetscBLASInt min_MN = std::min(M,N);
560 
561  // NRHS
562  // The number of right hand sides, i.e., the number of columns
563  // of the matrices B and X. NRHS >= 0.
564  // This could later be generalized to solve for multiple right-hand
565  // sides...
566  PetscBLASInt NRHS = 1;
567 
568  // A is double precision array, dimension (LDA,N)
569  // On entry, the M-by-N matrix A.
570  // On exit, the first min(m,n) rows of A are overwritten with
571  // its right singular vectors, stored rowwise.
572  //
573  // The data vector that will be passed to Lapack.
574  std::vector<T> & A_trans_vals = A_trans.get_values();
575 
576  // LDA
577  // The leading dimension of the array A. LDA >= max(1,M).
578  PetscBLASInt LDA = M;
579 
580  // B is double precision array, dimension (LDB,NRHS)
581  // On entry, the M-by-NRHS right hand side matrix B.
582  // On exit, B is overwritten by the N-by-NRHS solution
583  // matrix X. If m >= n and RANK = n, the residual
584  // sum-of-squares for the solution in the i-th column is given
585  // by the sum of squares of elements n+1:m in that column.
586  //
587  // Since we don't want the user's rhs vector to be overwritten by
588  // the solution, we copy the rhs values into the solution vector "x"
589  // now. x needs to be long enough to hold both the (Nx1) solution
590  // vector or the (Mx1) rhs, so size it to the max of those.
591  x.resize(max_MN);
592  for (auto i : IntRange<int>(0, rhs.size()))
593  x(i) = rhs(i);
594 
595  // Make the syntax below simpler by grabbing a reference to this array.
596  std::vector<T> & B = x.get_values();
597 
598  // LDB
599  // The leading dimension of the array B. LDB >= max(1,max(M,N)).
600  PetscBLASInt LDB = x.size();
601 
602  // S is double precision array, dimension (min(M,N))
603  // The singular values of A in decreasing order.
604  // The condition number of A in the 2-norm = S(1)/S(min(m,n)).
605  std::vector<T> S(min_MN);
606 
607  // RCOND
608  // Used to determine the effective rank of A. Singular values
609  // S(i) <= RCOND*S(1) are treated as zero. If RCOND < 0, machine
610  // precision is used instead.
611  PetscScalar RCOND = rcond;
612 
613  // RANK
614  // The effective rank of A, i.e., the number of singular values
615  // which are greater than RCOND*S(1).
616  PetscBLASInt RANK = 0;
617 
618  // LWORK
619  // The dimension of the array WORK. LWORK >= 1, and also:
620  // LWORK >= 3*min(M,N) + max( 2*min(M,N), max(M,N), NRHS )
621  // For good performance, LWORK should generally be larger.
622  //
623  // If LWORK = -1, then a workspace query is assumed; the routine
624  // only calculates the optimal size of the WORK array, returns
625  // this value as the first entry of the WORK array, and no error
626  // message related to LWORK is issued by XERBLA.
627  //
628  // The factor of 3/2 is arbitrary and is used to satisfy the "should
629  // generally be larger" clause.
630  PetscBLASInt LWORK = (3*min_MN + std::max(2*min_MN, std::max(max_MN, NRHS))) * 3/2;
631 
632  // WORK is double precision array, dimension (MAX(1,LWORK))
633  // On exit, if INFO = 0, WORK(1) returns the optimal LWORK.
634  std::vector<T> WORK(LWORK);
635 
636  // INFO
637  // = 0: successful exit
638  // < 0: if INFO = -i, the i-th argument had an illegal value.
639  // > 0: the algorithm for computing the SVD failed to converge;
640  // if INFO = i, i off-diagonal elements of an intermediate
641  // bidiagonal form did not converge to zero.
642  PetscBLASInt INFO = 0;
643 
644  // LAPACKgelss_(const PetscBLASInt *, // M
645  // const PetscBLASInt *, // N
646  // const PetscBLASInt *, // NRHS
647  // PetscScalar *, // A
648  // const PetscBLASInt *, // LDA
649  // PetscScalar *, // B
650  // const PetscBLASInt *, // LDB
651  // PetscReal *, // S(out) = singular values of A in increasing order
652  // const PetscReal *, // RCOND = tolerance for singular values
653  // PetscBLASInt *, // RANK(out) = number of "non-zero" singular values
654  // PetscScalar *, // WORK
655  // const PetscBLASInt *, // LWORK
656  // PetscBLASInt *); // INFO
657  LAPACKgelss_(&M, &N, &NRHS, pPS(A_trans_vals.data()), &LDA,
658  pPS(B.data()), &LDB, pPS(S.data()), &RCOND, &RANK,
659  pPS(WORK.data()), &LWORK, &INFO);
660 
661  // Check for errors in the Lapack call
662  if (INFO < 0)
663  libmesh_error_msg("Error, argument " << -INFO << " to LAPACKgelss_ had an illegal value.");
664  if (INFO > 0)
665  libmesh_error_msg("The algorithm for computing the SVD failed to converge!");
666 
667  // Debugging: print singular values and information about condition number:
668  // libMesh::err << "RCOND=" << RCOND << std::endl;
669  // libMesh::err << "Singular values: " << std::endl;
670  // for (auto i : index_range(S))
671  // libMesh::err << S[i] << std::endl;
672  // libMesh::err << "The condition number of A is approximately: " << S[0]/S.back() << std::endl;
673 
674  // Lapack has already written the solution into B, but it will be
675  // the wrong size for non-square problems, so we need to resize it
676  // correctly. The size of the solution vector should be the number
677  // of columns of the original A matrix. Unfortunately, resizing a
678  // DenseVector currently also zeros it out (unlike a std::vector) so
679  // we'll resize the underlying storage directly (the size is not
680  // stored independently elsewhere).
681  x.get_values().resize(this->n());
682 }

◆ add() [1/2]

template<typename T >
template<typename T2 , typename T3 >
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type libMesh::DenseMatrix< T >::add ( const T2  factor,
const DenseMatrix< T3 > &  mat 
)
inline

Adds factor times mat to this matrix.

Returns
A reference to *this.

Definition at line 945 of file dense_matrix.h.

947 {
948  libmesh_assert_equal_to (this->m(), mat.m());
949  libmesh_assert_equal_to (this->n(), mat.n());
950 
951  for (auto i : IntRange<unsigned int>(0, this->m()))
952  for (auto j : IntRange<unsigned int>(0, this->n()))
953  (*this)(i,j) += factor * mat(i,j);
954 }

Referenced by assemble_wave(), libMesh::FEMSystem::assembly(), LinearElasticityWithContact::compute_stresses(), LargeDeformationElasticity::compute_stresses(), libMesh::TransientRBEvaluation::rb_solve(), and libMesh::RBEvaluation::rb_solve().

◆ add() [2/2]

template<typename T >
template<typename T2 , typename T3 >
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type libMesh::DenseMatrixBase< T >::add ( const T2  factor,
const DenseMatrixBase< T3 > &  mat 
)
inlineinherited

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 195 of file dense_matrix_base.h.

197 {
198  libmesh_assert_equal_to (this->m(), mat.m());
199  libmesh_assert_equal_to (this->n(), mat.n());
200 
201  for (auto j : IntRange<unsigned int>(0, this->n()))
202  for (auto i : IntRange<unsigned int>(0, this->m()))
203  this->el(i,j) += factor*mat.el(i,j);
204 }

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

◆ cholesky_solve()

template<typename T >
template<typename T2 >
template void libMesh::DenseMatrix< T >::cholesky_solve ( const DenseVector< T2 > &  b,
DenseVector< T2 > &  x 
)

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
This method may also be used when A is real-valued and x and b are complex-valued.

Definition at line 947 of file dense_matrix_impl.h.

949 {
950  // Check for a previous decomposition
951  switch(this->_decomposition_type)
952  {
953  case NONE:
954  {
955  this->_cholesky_decompose ();
956  break;
957  }
958 
959  case CHOLESKY:
960  {
961  // Already factored, just need to call back_substitute.
962  break;
963  }
964 
965  default:
966  libmesh_error_msg("Error! This matrix already has a different decomposition...");
967  }
968 
969  // Perform back substitution
970  this->_cholesky_back_substitute (b, x);
971 }

Referenced by libMesh::FEGenericBase< FEOutputType< T >::type >::coarsened_dof_values(), libMesh::FEGenericBase< FEOutputType< T >::type >::compute_periodic_constraints(), libMesh::FEGenericBase< FEOutputType< T >::type >::compute_proj_constraints(), LinearElasticity::compute_stresses(), libMesh::GenericProjector< FFunctor, GFunctor, FValue, ProjectionAction >::SubProjector::construct_projection(), libMesh::BoundaryProjectSolution::operator()(), and libMesh::HPCoarsenTest::select_refinement().

◆ condense() [1/2]

template<typename T>
void libMesh::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 384 of file dense_matrix.h.

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

◆ condense() [2/2]

template<typename T >
void libMesh::DenseMatrixBase< T >::condense ( const unsigned int  i,
const unsigned int  j,
const T  val,
DenseVectorBase< T > &  rhs 
)
protectedinherited

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 73 of file dense_matrix_base_impl.h.

77  {
78  libmesh_assert_equal_to (this->_m, rhs.size());
79  libmesh_assert_equal_to (iv, jv);
80 
81 
82  // move the known value into the RHS
83  // and zero the column
84  for (auto i : IntRange<unsigned int>(0, this->m()))
85  {
86  rhs.el(i) -= this->el(i,jv)*val;
87  this->el(i,jv) = 0.;
88  }
89 
90  // zero the row
91  for (auto j : IntRange<unsigned int>(0, this->n()))
92  this->el(iv,j) = 0.;
93 
94  this->el(iv,jv) = 1.;
95  rhs.el(iv) = val;
96 
97  }

References libMesh::DenseVectorBase< T >::el(), and libMesh::DenseVectorBase< T >::size().

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

◆ det()

template<typename T >
T libMesh::DenseMatrix< T >::det ( )
Returns
The determinant of the matrix.
Note
Implemented by computing an LU decomposition and then taking the product of the diagonal terms. Therefore this is a non-const method which modifies the entries of the matrix.

Definition at line 886 of file dense_matrix_impl.h.

887 {
888  switch(this->_decomposition_type)
889  {
890  case NONE:
891  {
892  // First LU decompose the matrix.
893  // Note that the lu_decompose routine will check to see if the
894  // matrix is square so we don't worry about it.
895  if (this->use_blas_lapack)
896  this->_lu_decompose_lapack();
897  else
898  this->_lu_decompose ();
899  }
900  case LU:
901  case LU_BLAS_LAPACK:
902  {
903  // Already decomposed, don't do anything
904  break;
905  }
906  default:
907  libmesh_error_msg("Error! Can't compute the determinant under the current decomposition.");
908  }
909 
910  // A variable to keep track of the running product of diagonal terms.
911  T determinant = 1.;
912 
913  // Loop over diagonal terms, computing the product. In practice,
914  // be careful because this value could easily become too large to
915  // fit in a double or float. To be safe, one should keep track of
916  // the power (of 10) of the determinant in a separate variable
917  // and maintain an order 1 value for the determinant itself.
918  unsigned int n_interchanges = 0;
919  for (auto i : IntRange<unsigned int>(0, this->m()))
920  {
921  if (this->_decomposition_type==LU)
922  if (_pivots[i] != static_cast<pivot_index_t>(i))
923  n_interchanges++;
924 
925  // Lapack pivots are 1-based!
927  if (_pivots[i] != static_cast<pivot_index_t>(i+1))
928  n_interchanges++;
929 
930  determinant *= (*this)(i,i);
931  }
932 
933  // Compute sign of determinant, depends on number of row interchanges!
934  // The sign should be (-1)^{n}, where n is the number of interchanges.
935  Real sign = n_interchanges % 2 == 0 ? 1. : -1.;
936 
937  return sign*determinant;
938 }

Referenced by LargeDeformationElasticity::compute_stresses().

◆ diagonal()

template<typename T >
DenseVector< T > libMesh::DenseMatrixBase< T >::diagonal ( ) const
inherited

Return the matrix diagonal.

Definition at line 37 of file dense_matrix_base_impl.h.

38  {
39  DenseVector<T> ret(_m);
40  for (decltype(_m) i = 0; i < _m; ++i)
41  ret(i) = el(i, i);
42  return ret;
43  }

Referenced by libMesh::DiagonalMatrix< T >::add_matrix().

◆ el() [1/2]

template<typename T>
virtual T libMesh::DenseMatrix< T >::el ( const unsigned int  i,
const unsigned int  j 
) const
inlineoverridevirtual
Returns
The (i,j) element of the matrix. Since internal data representations may differ, you must redefine this function.

Implements libMesh::DenseMatrixBase< T >.

Definition at line 118 of file dense_matrix.h.

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

Referenced by libMesh::RBConstruction::add_scaled_matrix_and_vector().

◆ el() [2/2]

template<typename T>
virtual T& libMesh::DenseMatrix< T >::el ( const unsigned int  i,
const unsigned int  j 
)
inlineoverridevirtual
Returns
The (i,j) element of the matrix as a writable reference. Since internal data representations may differ, you must redefine this function.

Implements libMesh::DenseMatrixBase< T >.

Definition at line 122 of file dense_matrix.h.

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

◆ evd()

template<typename T>
void libMesh::DenseMatrix< T >::evd ( DenseVector< T > &  lambda_real,
DenseVector< T > &  lambda_imag 
)

Compute the eigenvalues (both real and imaginary parts) of a general matrix.

Warning: the contents of *this are overwritten by this function!

The implementation requires the LAPACKgeev_ function which is wrapped by PETSc.

Definition at line 842 of file dense_matrix_impl.h.

844 {
845  // We use the LAPACK eigenvalue problem implementation
846  _evd_lapack(lambda_real, lambda_imag);
847 }

◆ evd_left()

template<typename T>
void libMesh::DenseMatrix< T >::evd_left ( DenseVector< T > &  lambda_real,
DenseVector< T > &  lambda_imag,
DenseMatrix< T > &  VL 
)

Compute the eigenvalues (both real and imaginary parts) and left eigenvectors of a general matrix, \( A \).

Warning: the contents of *this are overwritten by this function!

The left eigenvector \( u_j \) of \( A \) satisfies: \( u_j^H A = lambda_j u_j^H \) where \( u_j^H \) denotes the conjugate-transpose of \( u_j \).

If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then the j-th and (j+1)-st columns of VL "share" their real-valued storage in the following way: u_j = VL(:,j) + i*VL(:,j+1) and u_{j+1} = VL(:,j) - i*VL(:,j+1).

The implementation requires the LAPACKgeev_ routine which is provided by PETSc.

Definition at line 852 of file dense_matrix_impl.h.

855 {
856  // We use the LAPACK eigenvalue problem implementation
857  _evd_lapack(lambda_real, lambda_imag, &VL, nullptr);
858 }

◆ evd_left_and_right()

template<typename T>
void libMesh::DenseMatrix< T >::evd_left_and_right ( DenseVector< T > &  lambda_real,
DenseVector< T > &  lambda_imag,
DenseMatrix< T > &  VL,
DenseMatrix< T > &  VR 
)

Compute the eigenvalues (both real and imaginary parts) as well as the left and right eigenvectors of a general matrix.

Warning: the contents of *this are overwritten by this function!

See the documentation of the evd_left() and evd_right() functions for more information. The implementation requires the LAPACKgeev_ routine which is provided by PETSc.

Definition at line 874 of file dense_matrix_impl.h.

878 {
879  // We use the LAPACK eigenvalue problem implementation
880  _evd_lapack(lambda_real, lambda_imag, &VL, &VR);
881 }

Referenced by DenseMatrixTest::testEVD_helper().

◆ evd_right()

template<typename T>
void libMesh::DenseMatrix< T >::evd_right ( DenseVector< T > &  lambda_real,
DenseVector< T > &  lambda_imag,
DenseMatrix< T > &  VR 
)

Compute the eigenvalues (both real and imaginary parts) and right eigenvectors of a general matrix, \( A \).

Warning: the contents of *this are overwritten by this function!

The right eigenvector \( v_j \) of \( A \) satisfies: \( A v_j = lambda_j v_j \) where \( lambda_j \) is its corresponding eigenvalue.

Note
If the j-th and (j+1)-st eigenvalues form a complex conjugate pair, then the j-th and (j+1)-st columns of VR "share" their real-valued storage in the following way: v_j = VR(:,j) + i*VR(:,j+1) and v_{j+1} = VR(:,j) - i*VR(:,j+1).

The implementation requires the LAPACKgeev_ routine which is provided by PETSc.

Definition at line 863 of file dense_matrix_impl.h.

866 {
867  // We use the LAPACK eigenvalue problem implementation
868  _evd_lapack(lambda_real, lambda_imag, nullptr, &VR);
869 }

◆ get_principal_submatrix() [1/2]

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

Put the sub_m x sub_m principal submatrix into dest.

Definition at line 604 of file dense_matrix_impl.h.

605 {
606  get_principal_submatrix(sub_m, sub_m, dest);
607 }

◆ get_principal_submatrix() [2/2]

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

Put the sub_m x sub_n principal submatrix into dest.

Definition at line 574 of file dense_matrix_impl.h.

577 {
578  libmesh_assert( (sub_m <= this->m()) && (sub_n <= this->n()) );
579 
580  dest.resize(sub_m, sub_n);
581  for (unsigned int i=0; i<sub_m; i++)
582  for (unsigned int j=0; j<sub_n; j++)
583  dest(i,j) = (*this)(i,j);
584 }

Referenced by libMesh::RBEIMConstruction::compute_best_fit_error(), libMesh::RBEIMEvaluation::rb_solve(), and libMesh::TransientRBConstruction::update_RB_initial_condition_all_N().

◆ get_transpose()

template<typename T>
void libMesh::DenseMatrix< T >::get_transpose ( DenseMatrix< T > &  dest) const

Put the tranposed matrix into dest.

Definition at line 612 of file dense_matrix_impl.h.

613 {
614  dest.resize(this->n(), this->m());
615 
616  for (auto i : IntRange<unsigned int>(0, dest.m()))
617  for (auto j : IntRange<unsigned int>(0, dest.n()))
618  dest(i,j) = (*this)(j,i);
619 }

Referenced by libMesh::RBConstruction::add_scaled_matrix_and_vector().

◆ get_values() [1/2]

template<typename T>
std::vector<T>& libMesh::DenseMatrix< T >::get_values ( )
inline
Returns
A reference to the underlying data storage vector.

This should be used with caution (i.e. one should not change the size of the vector, etc.) but is useful for interoperating with low level BLAS routines which expect a simple array.

Definition at line 371 of file dense_matrix.h.

371 { return _val; }

Referenced by libMesh::DenseMatrix< Real >::_evd_lapack(), libMesh::DenseMatrix< Real >::_matvec_blas(), libMesh::DenseMatrix< Real >::_svd_lapack(), libMesh::DenseMatrix< Real >::_svd_solve_lapack(), libMesh::PetscMatrix< libMesh::Number >::add_block_matrix(), libMesh::EpetraMatrix< T >::add_matrix(), libMesh::PetscMatrix< libMesh::Number >::add_matrix(), and OverlappingCouplingGhostingTest::run_sparsity_pattern_test().

◆ get_values() [2/2]

template<typename T>
const std::vector<T>& libMesh::DenseMatrix< T >::get_values ( ) const
inline
Returns
A constant reference to the underlying data storage vector.

Definition at line 376 of file dense_matrix.h.

376 { return _val; }

◆ l1_norm()

template<typename T>
auto libMesh::DenseMatrix< T >::l1_norm ( ) const -> decltype(std::abs(T(0)))
inline
Returns
The l1-norm of the matrix, that is, the max column sum:

\( |M|_1 = max_{all columns j} \sum_{all rows i} |M_ij| \),

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 1052 of file dense_matrix.h.

1053 {
1054  libmesh_assert (this->_m);
1055  libmesh_assert (this->_n);
1056 
1057  auto columnsum = std::abs(T(0));
1058  for (unsigned int i=0; i!=this->_m; i++)
1059  {
1060  columnsum += std::abs((*this)(i,0));
1061  }
1062  auto my_max = columnsum;
1063  for (unsigned int j=1; j!=this->_n; j++)
1064  {
1065  columnsum = 0.;
1066  for (unsigned int i=0; i!=this->_m; i++)
1067  {
1068  columnsum += std::abs((*this)(i,j));
1069  }
1070  my_max = (my_max > columnsum? my_max : columnsum);
1071  }
1072  return my_max;
1073 }

Referenced by libMesh::FEMSystem::assembly().

◆ left_multiply() [1/2]

template<typename T>
void libMesh::DenseMatrix< T >::left_multiply ( const DenseMatrixBase< T > &  M2)
overridevirtual

Performs the operation: (*this) <- M2 * (*this)

Implements libMesh::DenseMatrixBase< T >.

Definition at line 58 of file dense_matrix_impl.h.

59 {
60  if (this->use_blas_lapack)
61  this->_multiply_blas(M2, LEFT_MULTIPLY);
62  else
63  {
64  // (*this) <- M2 * (*this)
65  // Where:
66  // (*this) = (m x n),
67  // M2 = (m x p),
68  // M3 = (p x n)
69 
70  // M3 is a copy of *this before it gets resize()d
71  DenseMatrix<T> M3(*this);
72 
73  // Resize *this so that the result can fit
74  this->resize (M2.m(), M3.n());
75 
76  // Call the multiply function in the base class
77  this->multiply(*this, M2, M3);
78  }
79 }

Referenced by LargeDeformationElasticity::compute_stresses().

◆ left_multiply() [2/2]

template<typename T >
template<typename T2 >
void libMesh::DenseMatrix< T >::left_multiply ( const DenseMatrixBase< T2 > &  M2)

Left multiplies by the matrix M2 of different type.

Definition at line 85 of file dense_matrix_impl.h.

86 {
87  // (*this) <- M2 * (*this)
88  // Where:
89  // (*this) = (m x n),
90  // M2 = (m x p),
91  // M3 = (p x n)
92 
93  // M3 is a copy of *this before it gets resize()d
94  DenseMatrix<T> M3(*this);
95 
96  // Resize *this so that the result can fit
97  this->resize (M2.m(), M3.n());
98 
99  // Call the multiply function in the base class
100  this->multiply(*this, M2, M3);
101 }

◆ left_multiply_transpose() [1/2]

template<typename T>
void libMesh::DenseMatrix< T >::left_multiply_transpose ( const DenseMatrix< T > &  A)

Left multiplies by the transpose of the matrix A.

Definition at line 106 of file dense_matrix_impl.h.

107 {
108  if (this->use_blas_lapack)
110  else
111  {
112  //Check to see if we are doing (A^T)*A
113  if (this == &A)
114  {
115  //libmesh_here();
116  DenseMatrix<T> B(*this);
117 
118  // Simple but inefficient way
119  // return this->left_multiply_transpose(B);
120 
121  // More efficient, but more code way
122  // If A is mxn, the result will be a square matrix of Size n x n.
123  const unsigned int n_rows = A.m();
124  const unsigned int n_cols = A.n();
125 
126  // resize() *this and also zero out all entries.
127  this->resize(n_cols,n_cols);
128 
129  // Compute the lower-triangular part
130  for (unsigned int i=0; i<n_cols; ++i)
131  for (unsigned int j=0; j<=i; ++j)
132  for (unsigned int k=0; k<n_rows; ++k) // inner products are over n_rows
133  (*this)(i,j) += B(k,i)*B(k,j);
134 
135  // Copy lower-triangular part into upper-triangular part
136  for (unsigned int i=0; i<n_cols; ++i)
137  for (unsigned int j=i+1; j<n_cols; ++j)
138  (*this)(i,j) = (*this)(j,i);
139  }
140 
141  else
142  {
143  DenseMatrix<T> B(*this);
144 
145  this->resize (A.n(), B.n());
146 
147  libmesh_assert_equal_to (A.m(), B.m());
148  libmesh_assert_equal_to (this->m(), A.n());
149  libmesh_assert_equal_to (this->n(), B.n());
150 
151  const unsigned int m_s = A.n();
152  const unsigned int p_s = A.m();
153  const unsigned int n_s = this->n();
154 
155  // Do it this way because there is a
156  // decent chance (at least for constraint matrices)
157  // that A.transpose(i,k) = 0.
158  for (unsigned int i=0; i<m_s; i++)
159  for (unsigned int k=0; k<p_s; k++)
160  if (A.transpose(i,k) != 0.)
161  for (unsigned int j=0; j<n_s; j++)
162  (*this)(i,j) += A.transpose(i,k)*B(k,j);
163  }
164  }
165 
166 }

◆ left_multiply_transpose() [2/2]

template<typename T >
template<typename T2 >
void libMesh::DenseMatrix< T >::left_multiply_transpose ( const DenseMatrix< T2 > &  A)

Left multiplies by the transpose of the matrix A which contains a different numerical type.

Definition at line 172 of file dense_matrix_impl.h.

173 {
174  //Check to see if we are doing (A^T)*A
175  if (this == &A)
176  {
177  //libmesh_here();
178  DenseMatrix<T> B(*this);
179 
180  // Simple but inefficient way
181  // return this->left_multiply_transpose(B);
182 
183  // More efficient, but more code way
184  // If A is mxn, the result will be a square matrix of Size n x n.
185  const unsigned int n_rows = A.m();
186  const unsigned int n_cols = A.n();
187 
188  // resize() *this and also zero out all entries.
189  this->resize(n_cols,n_cols);
190 
191  // Compute the lower-triangular part
192  for (unsigned int i=0; i<n_cols; ++i)
193  for (unsigned int j=0; j<=i; ++j)
194  for (unsigned int k=0; k<n_rows; ++k) // inner products are over n_rows
195  (*this)(i,j) += B(k,i)*B(k,j);
196 
197  // Copy lower-triangular part into upper-triangular part
198  for (unsigned int i=0; i<n_cols; ++i)
199  for (unsigned int j=i+1; j<n_cols; ++j)
200  (*this)(i,j) = (*this)(j,i);
201  }
202 
203  else
204  {
205  DenseMatrix<T> B(*this);
206 
207  this->resize (A.n(), B.n());
208 
209  libmesh_assert_equal_to (A.m(), B.m());
210  libmesh_assert_equal_to (this->m(), A.n());
211  libmesh_assert_equal_to (this->n(), B.n());
212 
213  const unsigned int m_s = A.n();
214  const unsigned int p_s = A.m();
215  const unsigned int n_s = this->n();
216 
217  // Do it this way because there is a
218  // decent chance (at least for constraint matrices)
219  // that A.transpose(i,k) = 0.
220  for (unsigned int i=0; i<m_s; i++)
221  for (unsigned int k=0; k<p_s; k++)
222  if (A.transpose(i,k) != 0.)
223  for (unsigned int j=0; j<n_s; j++)
224  (*this)(i,j) += A.transpose(i,k)*B(k,j);
225  }
226 }

◆ linfty_norm()

template<typename T>
auto libMesh::DenseMatrix< T >::linfty_norm ( ) const -> decltype(std::abs(T(0)))
inline
Returns
The linfty-norm of the matrix, that is, the max row sum:

\( |M|_\infty = max_{all rows i} \sum_{all columns j} |M_ij| \),

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 1079 of file dense_matrix.h.

1080 {
1081  libmesh_assert (this->_m);
1082  libmesh_assert (this->_n);
1083 
1084  auto rowsum = std::abs(T(0));
1085  for (unsigned int j=0; j!=this->_n; j++)
1086  {
1087  rowsum += std::abs((*this)(0,j));
1088  }
1089  auto my_max = rowsum;
1090  for (unsigned int i=1; i!=this->_m; i++)
1091  {
1092  rowsum = 0.;
1093  for (unsigned int j=0; j!=this->_n; j++)
1094  {
1095  rowsum += std::abs((*this)(i,j));
1096  }
1097  my_max = (my_max > rowsum? my_max : rowsum);
1098  }
1099  return my_max;
1100 }

◆ lu_solve()

template<typename T>
void libMesh::DenseMatrix< T >::lu_solve ( const DenseVector< T > &  b,
DenseVector< T > &  x 
)

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

Partial pivoting is performed by default in order to keep the algorithm stable to the effects of round-off error.

Definition at line 625 of file dense_matrix_impl.h.

627 {
628  // Check to be sure that the matrix is square before attempting
629  // an LU-solve. In general, one can compute the LU factorization of
630  // a non-square matrix, but:
631  //
632  // Overdetermined systems (m>n) have a solution only if enough of
633  // the equations are linearly-dependent.
634  //
635  // Underdetermined systems (m<n) typically have infinitely many
636  // solutions.
637  //
638  // We don't want to deal with either of these ambiguous cases here...
639  libmesh_assert_equal_to (this->m(), this->n());
640 
641  switch(this->_decomposition_type)
642  {
643  case NONE:
644  {
645  if (this->use_blas_lapack)
646  this->_lu_decompose_lapack();
647  else
648  this->_lu_decompose ();
649  break;
650  }
651 
652  case LU_BLAS_LAPACK:
653  {
654  // Already factored, just need to call back_substitute.
655  if (this->use_blas_lapack)
656  break;
657  }
658  libmesh_fallthrough();
659 
660  case LU:
661  {
662  // Already factored, just need to call back_substitute.
663  if (!(this->use_blas_lapack))
664  break;
665  }
666  libmesh_fallthrough();
667 
668  default:
669  libmesh_error_msg("Error! This matrix already has a different decomposition...");
670  }
671 
672  if (this->use_blas_lapack)
673  this->_lu_back_substitute_lapack (b, x);
674  else
675  this->_lu_back_substitute (b, x);
676 }

Referenced by libMesh::RBEIMConstruction::compute_best_fit_error(), libMesh::WeightedPatchRecoveryErrorEstimator::EstimateError::operator()(), libMesh::PatchRecoveryErrorEstimator::EstimateError::operator()(), libMesh::TransientRBEvaluation::rb_solve(), libMesh::RBEvaluation::rb_solve(), libMesh::RBEIMEvaluation::rb_solve(), libMesh::TransientRBEvaluation::rb_solve_again(), libMesh::TransientRBConstruction::set_error_temporal_data(), and libMesh::TransientRBConstruction::update_RB_initial_condition_all_N().

◆ m()

template<typename T>
unsigned int libMesh::DenseMatrixBase< T >::m ( ) const
inlineinherited

◆ max()

template<typename T>
auto libMesh::DenseMatrix< T >::max ( ) const -> decltype(libmesh_real(T(0)))
inline
Returns
The maximum entry in the matrix, or the maximum real part in the case of complex numbers.

Definition at line 1031 of file dense_matrix.h.

1032 {
1033  libmesh_assert (this->_m);
1034  libmesh_assert (this->_n);
1035  auto my_max = libmesh_real((*this)(0,0));
1036 
1037  for (unsigned int i=0; i!=this->_m; i++)
1038  {
1039  for (unsigned int j=0; j!=this->_n; j++)
1040  {
1041  auto current = libmesh_real((*this)(i,j));
1042  my_max = (my_max > current? my_max : current);
1043  }
1044  }
1045  return my_max;
1046 }

◆ min()

template<typename T>
auto libMesh::DenseMatrix< T >::min ( ) const -> decltype(libmesh_real(T(0)))
inline
Returns
The minimum entry in the matrix, or the minimum real part in the case of complex numbers.

Definition at line 1010 of file dense_matrix.h.

1011 {
1012  libmesh_assert (this->_m);
1013  libmesh_assert (this->_n);
1014  auto my_min = libmesh_real((*this)(0,0));
1015 
1016  for (unsigned int i=0; i!=this->_m; i++)
1017  {
1018  for (unsigned int j=0; j!=this->_n; j++)
1019  {
1020  auto current = libmesh_real((*this)(i,j));
1021  my_min = (my_min < current? my_min : current);
1022  }
1023  }
1024  return my_min;
1025 }

◆ multiply()

template<typename T >
void libMesh::DenseMatrixBase< T >::multiply ( DenseMatrixBase< T > &  M1,
const DenseMatrixBase< T > &  M2,
const DenseMatrixBase< T > &  M3 
)
staticprotectedinherited

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

Definition at line 46 of file dense_matrix_base_impl.h.

49  {
50  // Assertions to make sure we have been
51  // passed matrices of the correct dimension.
52  libmesh_assert_equal_to (M1.m(), M2.m());
53  libmesh_assert_equal_to (M1.n(), M3.n());
54  libmesh_assert_equal_to (M2.n(), M3.m());
55 
56  const unsigned int m_s = M2.m();
57  const unsigned int p_s = M2.n();
58  const unsigned int n_s = M1.n();
59 
60  // Do it this way because there is a
61  // decent chance (at least for constraint matrices)
62  // that M3(k,j) = 0. when right-multiplying.
63  for (unsigned int k=0; k<p_s; k++)
64  for (unsigned int j=0; j<n_s; j++)
65  if (M3.el(k,j) != 0.)
66  for (unsigned int i=0; i<m_s; i++)
67  M1.el(i,j) += M2.el(i,k) * M3.el(k,j);
68  }

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

◆ n()

template<typename T>
unsigned int libMesh::DenseMatrixBase< T >::n ( ) const
inlineinherited

◆ operator!=()

template<typename T>
bool libMesh::DenseMatrix< T >::operator!= ( const DenseMatrix< T > &  mat) const
inline
Returns
true if mat is not exactly equal to this matrix, false otherwise.

Definition at line 973 of file dense_matrix.h.

974 {
975  for (auto i : index_range(_val))
976  if (_val[i] != mat._val[i])
977  return true;
978 
979  return false;
980 }

◆ operator()() [1/2]

template<typename T >
T & libMesh::DenseMatrix< T >::operator() ( const unsigned int  i,
const unsigned int  j 
)
inline
Returns
The (i,j) element of the matrix as a writable reference.

Definition at line 896 of file dense_matrix.h.

898 {
899  libmesh_assert_less (i*j, _val.size());
900  libmesh_assert_less (i, this->_m);
901  libmesh_assert_less (j, this->_n);
902 
903  //return _val[(i) + (this->_m)*(j)]; // col-major
904  return _val[(i)*(this->_n) + (j)]; // row-major
905 }

◆ operator()() [2/2]

template<typename T >
T libMesh::DenseMatrix< T >::operator() ( const unsigned int  i,
const unsigned int  j 
) const
inline
Returns
The (i,j) element of the matrix.

Definition at line 880 of file dense_matrix.h.

882 {
883  libmesh_assert_less (i*j, _val.size());
884  libmesh_assert_less (i, this->_m);
885  libmesh_assert_less (j, this->_n);
886 
887 
888  // return _val[(i) + (this->_m)*(j)]; // col-major
889  return _val[(i)*(this->_n) + (j)]; // row-major
890 }

◆ operator*=()

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

Multiplies every element in the matrix by factor.

Returns
A reference to *this.

Definition at line 932 of file dense_matrix.h.

933 {
934  this->scale(factor);
935  return *this;
936 }

◆ operator+=()

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

Adds mat to this matrix.

Returns
A reference to *this.

Definition at line 986 of file dense_matrix.h.

987 {
988  for (auto i : index_range(_val))
989  _val[i] += mat._val[i];
990 
991  return *this;
992 }

◆ operator-=()

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

Subtracts mat from this matrix.

Returns
A reference to *this.

Definition at line 998 of file dense_matrix.h.

999 {
1000  for (auto i : index_range(_val))
1001  _val[i] -= mat._val[i];
1002 
1003  return *this;
1004 }

◆ operator=() [1/3]

template<typename T>
DenseMatrix& libMesh::DenseMatrix< T >::operator= ( const DenseMatrix< T > &  )
default

◆ operator=() [2/3]

template<typename T >
template<typename T2 >
DenseMatrix< T > & libMesh::DenseMatrix< T >::operator= ( const DenseMatrix< T2 > &  other_matrix)
inline

Assignment-from-other-matrix-type operator.

Copies the dense matrix of type T2 into the present matrix. This is useful for copying real matrices into complex ones for further operations.

Returns
A reference to *this.

Definition at line 807 of file dense_matrix.h.

808 {
809  unsigned int mat_m = mat.m(), mat_n = mat.n();
810  this->resize(mat_m, mat_n);
811  for (unsigned int i=0; i<mat_m; i++)
812  for (unsigned int j=0; j<mat_n; j++)
813  (*this)(i,j) = mat(i,j);
814 
815  return *this;
816 }

◆ operator=() [3/3]

template<typename T>
DenseMatrix& libMesh::DenseMatrix< T >::operator= ( DenseMatrix< T > &&  )
default

◆ operator==()

template<typename T>
bool libMesh::DenseMatrix< T >::operator== ( const DenseMatrix< T > &  mat) const
inline
Returns
true if mat is exactly equal to this matrix, false otherwise.

Definition at line 960 of file dense_matrix.h.

961 {
962  for (auto i : index_range(_val))
963  if (_val[i] != mat._val[i])
964  return false;
965 
966  return true;
967 }

◆ outer_product()

template<typename T>
void libMesh::DenseMatrix< T >::outer_product ( const DenseVector< T > &  a,
const DenseVector< T > &  b 
)

Computes the outer (dyadic) product of two vectors and stores in (*this).

The outer product of two real-valued vectors \(\mathbf{a}\) and \(\mathbf{b}\) is

\[ (\mathbf{a}\mathbf{b}^T)_{i,j} = \mathbf{a}_i \mathbf{b}_j . \]

The outer product of two complex-valued vectors \(\mathbf{a}\) and \(\mathbf{b}\) is

\[ (\mathbf{a}\mathbf{b}^H)_{i,j} = \mathbf{a}_i \mathbf{b}^*_j , \]

where \(H\) denotes the conjugate transpose of the vector and \(*\) denotes the complex conjugate.

Parameters
[in]aVector whose entries correspond to rows in the product matrix.
[in]bVector whose entries correspond to columns in the product matrix.

Definition at line 589 of file dense_matrix_impl.h.

591 {
592  const unsigned int m = a.size();
593  const unsigned int n = b.size();
594 
595  this->resize(m, n);
596  for (unsigned int i = 0; i < m; ++i)
597  for (unsigned int j = 0; j < n; ++j)
598  (*this)(i,j) = a(i) * libmesh_conj(b(j));
599 }

Referenced by DenseMatrixTest::testOuterProduct().

◆ print()

template<typename T >
void libMesh::DenseMatrixBase< T >::print ( std::ostream &  os = libMesh::out) const
inherited

Pretty-print the matrix, by default to libMesh::out.

Definition at line 125 of file dense_matrix_base_impl.h.

126  {
127  for (auto i : IntRange<unsigned int>(0, this->m()))
128  {
129  for (auto j : IntRange<unsigned int>(0, this->n()))
130  os << std::setw(8)
131  << this->el(i,j) << " ";
132 
133  os << std::endl;
134  }
135 
136  return;
137  }

◆ print_scientific()

template<typename T >
void libMesh::DenseMatrixBase< T >::print_scientific ( std::ostream &  os,
unsigned  precision = 8 
) const
inherited

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

Definition at line 101 of file dense_matrix_base_impl.h.

102  {
103  // save the initial format flags
104  std::ios_base::fmtflags os_flags = os.flags();
105 
106  // Print the matrix entries.
107  for (auto i : IntRange<unsigned int>(0, this->m()))
108  {
109  for (auto j : IntRange<unsigned int>(0, this->n()))
110  os << std::setw(15)
111  << std::scientific
112  << std::setprecision(precision)
113  << this->el(i,j) << " ";
114 
115  os << std::endl;
116  }
117 
118  // reset the original format flags
119  os.flags(os_flags);
120  }

◆ resize()

template<typename T >
void libMesh::DenseMatrix< T >::resize ( const unsigned int  new_m,
const unsigned int  new_n 
)
inline

Resize the matrix.

Will never free memory, but may allocate more. Sets all elements to 0.

Definition at line 822 of file dense_matrix.h.

824 {
825  _val.resize(new_m*new_n);
826 
827  this->_m = new_m;
828  this->_n = new_n;
829 
830  // zero and set decomposition_type to NONE
831  this->zero();
832 }

Referenced by libMesh::DenseMatrix< Real >::_evd_lapack(), libMesh::DenseMatrix< Real >::_svd_lapack(), libMesh::HPCoarsenTest::add_projection(), assemble(), LinearElasticity::assemble(), assemble_1D(), AssembleOptimization::assemble_A_and_F(), assemble_biharmonic(), assemble_cd(), assemble_elasticity(), assemble_ellipticdg(), assemble_helmholtz(), assemble_laplace(), assemble_mass(), assemble_matrices(), assemble_matrix_and_rhs(), assemble_poisson(), assemble_SchroedingerEquation(), assemble_shell(), assemble_stokes(), assemble_wave(), libMesh::DofMap::build_constraint_matrix(), libMesh::DofMap::build_constraint_matrix_and_vector(), libMesh::TransientRBEvaluation::cache_online_residual_terms(), NonlinearNeoHookeCurrentConfig::calculate_tangent(), libMesh::FEGenericBase< FEOutputType< T >::type >::coarsened_dof_values(), compute_jacobian(), libMesh::FEGenericBase< FEOutputType< T >::type >::compute_periodic_constraints(), libMesh::FEGenericBase< FEOutputType< T >::type >::compute_proj_constraints(), LinearElasticityWithContact::compute_stresses(), compute_stresses(), LargeDeformationElasticity::compute_stresses(), NonlinearNeoHookeCurrentConfig::get_linearized_stiffness(), libMesh::DenseMatrix< Real >::get_principal_submatrix(), NonlinearNeoHookeCurrentConfig::get_residual(), libMesh::DenseMatrix< Real >::get_transpose(), LaplaceYoung::jacobian(), LargeDeformationElasticity::jacobian(), libMesh::DGFEMContext::neighbor_side_fe_reinit(), libMesh::BoundaryProjectSolution::operator()(), libMesh::FEMContext::pre_fe_reinit(), libMesh::TransientRBEvaluation::rb_solve(), Biharmonic::JR::residual_and_jacobian(), LinearElasticityWithContact::residual_and_jacobian(), libMesh::DenseMatrix< Real >::resize(), libMesh::RBEIMEvaluation::resize_data_structures(), libMesh::TransientRBEvaluation::resize_data_structures(), libMesh::RBEvaluation::resize_data_structures(), OverlappingCouplingGhostingTest::run_sparsity_pattern_test(), and libMesh::HPCoarsenTest::select_refinement().

◆ right_multiply() [1/2]

template<typename T>
void libMesh::DenseMatrix< T >::right_multiply ( const DenseMatrixBase< T > &  M3)
overridevirtual

Performs the operation: (*this) <- (*this) * M3.

Implements libMesh::DenseMatrixBase< T >.

Definition at line 231 of file dense_matrix_impl.h.

232 {
233  if (this->use_blas_lapack)
234  this->_multiply_blas(M3, RIGHT_MULTIPLY);
235  else
236  {
237  // (*this) <- (*this) * M3
238  // Where:
239  // (*this) = (m x n),
240  // M2 = (m x p),
241  // M3 = (p x n)
242 
243  // M2 is a copy of *this before it gets resize()d
244  DenseMatrix<T> M2(*this);
245 
246  // Resize *this so that the result can fit
247  this->resize (M2.m(), M3.n());
248 
249  this->multiply(*this, M2, M3);
250  }
251 }

Referenced by libMesh::DofMap::build_constraint_matrix(), libMesh::DofMap::build_constraint_matrix_and_vector(), NonlinearNeoHookeCurrentConfig::get_linearized_stiffness(), and libMesh::FESubdivision::init_shape_functions().

◆ right_multiply() [2/2]

template<typename T >
template<typename T2 >
void libMesh::DenseMatrix< T >::right_multiply ( const DenseMatrixBase< T2 > &  M2)

Right multiplies by the matrix M2 of different type.

Definition at line 257 of file dense_matrix_impl.h.

258 {
259  // (*this) <- M3 * (*this)
260  // Where:
261  // (*this) = (m x n),
262  // M2 = (m x p),
263  // M3 = (p x n)
264 
265  // M2 is a copy of *this before it gets resize()d
266  DenseMatrix<T> M2(*this);
267 
268  // Resize *this so that the result can fit
269  this->resize (M2.m(), M3.n());
270 
271  this->multiply(*this, M2, M3);
272 }

◆ right_multiply_transpose() [1/2]

template<typename T>
void libMesh::DenseMatrix< T >::right_multiply_transpose ( const DenseMatrix< T > &  A)

Right multiplies by the transpose of the matrix A.

Definition at line 278 of file dense_matrix_impl.h.

279 {
280  if (this->use_blas_lapack)
282  else
283  {
284  //Check to see if we are doing B*(B^T)
285  if (this == &B)
286  {
287  //libmesh_here();
288  DenseMatrix<T> A(*this);
289 
290  // Simple but inefficient way
291  // return this->right_multiply_transpose(A);
292 
293  // More efficient, more code
294  // If B is mxn, the result will be a square matrix of Size m x m.
295  const unsigned int n_rows = B.m();
296  const unsigned int n_cols = B.n();
297 
298  // resize() *this and also zero out all entries.
299  this->resize(n_rows,n_rows);
300 
301  // Compute the lower-triangular part
302  for (unsigned int i=0; i<n_rows; ++i)
303  for (unsigned int j=0; j<=i; ++j)
304  for (unsigned int k=0; k<n_cols; ++k) // inner products are over n_cols
305  (*this)(i,j) += A(i,k)*A(j,k);
306 
307  // Copy lower-triangular part into upper-triangular part
308  for (unsigned int i=0; i<n_rows; ++i)
309  for (unsigned int j=i+1; j<n_rows; ++j)
310  (*this)(i,j) = (*this)(j,i);
311  }
312 
313  else
314  {
315  DenseMatrix<T> A(*this);
316 
317  this->resize (A.m(), B.m());
318 
319  libmesh_assert_equal_to (A.n(), B.n());
320  libmesh_assert_equal_to (this->m(), A.m());
321  libmesh_assert_equal_to (this->n(), B.m());
322 
323  const unsigned int m_s = A.m();
324  const unsigned int p_s = A.n();
325  const unsigned int n_s = this->n();
326 
327  // Do it this way because there is a
328  // decent chance (at least for constraint matrices)
329  // that B.transpose(k,j) = 0.
330  for (unsigned int j=0; j<n_s; j++)
331  for (unsigned int k=0; k<p_s; k++)
332  if (B.transpose(k,j) != 0.)
333  for (unsigned int i=0; i<m_s; i++)
334  (*this)(i,j) += A(i,k)*B.transpose(k,j);
335  }
336  }
337 }

Referenced by LargeDeformationElasticity::compute_stresses(), and NonlinearNeoHookeCurrentConfig::get_linearized_stiffness().

◆ right_multiply_transpose() [2/2]

template<typename T >
template<typename T2 >
void libMesh::DenseMatrix< T >::right_multiply_transpose ( const DenseMatrix< T2 > &  A)

Right multiplies by the transpose of the matrix A which contains a different numerical type.

Definition at line 343 of file dense_matrix_impl.h.

344 {
345  //Check to see if we are doing B*(B^T)
346  if (this == &B)
347  {
348  //libmesh_here();
349  DenseMatrix<T> A(*this);
350 
351  // Simple but inefficient way
352  // return this->right_multiply_transpose(A);
353 
354  // More efficient, more code
355  // If B is mxn, the result will be a square matrix of Size m x m.
356  const unsigned int n_rows = B.m();
357  const unsigned int n_cols = B.n();
358 
359  // resize() *this and also zero out all entries.
360  this->resize(n_rows,n_rows);
361 
362  // Compute the lower-triangular part
363  for (unsigned int i=0; i<n_rows; ++i)
364  for (unsigned int j=0; j<=i; ++j)
365  for (unsigned int k=0; k<n_cols; ++k) // inner products are over n_cols
366  (*this)(i,j) += A(i,k)*A(j,k);
367 
368  // Copy lower-triangular part into upper-triangular part
369  for (unsigned int i=0; i<n_rows; ++i)
370  for (unsigned int j=i+1; j<n_rows; ++j)
371  (*this)(i,j) = (*this)(j,i);
372  }
373 
374  else
375  {
376  DenseMatrix<T> A(*this);
377 
378  this->resize (A.m(), B.m());
379 
380  libmesh_assert_equal_to (A.n(), B.n());
381  libmesh_assert_equal_to (this->m(), A.m());
382  libmesh_assert_equal_to (this->n(), B.m());
383 
384  const unsigned int m_s = A.m();
385  const unsigned int p_s = A.n();
386  const unsigned int n_s = this->n();
387 
388  // Do it this way because there is a
389  // decent chance (at least for constraint matrices)
390  // that B.transpose(k,j) = 0.
391  for (unsigned int j=0; j<n_s; j++)
392  for (unsigned int k=0; k<p_s; k++)
393  if (B.transpose(k,j) != 0.)
394  for (unsigned int i=0; i<m_s; i++)
395  (*this)(i,j) += A(i,k)*B.transpose(k,j);
396  }
397 }

◆ scale()

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

Multiplies every element in the matrix by factor.

Definition at line 913 of file dense_matrix.h.

914 {
915  for (auto & v : _val)
916  v *= factor;
917 }

Referenced by LinearElasticityWithContact::compute_stresses(), compute_stresses(), LargeDeformationElasticity::compute_stresses(), and SolidSystem::element_time_derivative().

◆ scale_column()

template<typename T>
void libMesh::DenseMatrix< T >::scale_column ( const unsigned int  col,
const T  factor 
)
inline

Multiplies every element in the column col matrix by factor.

Definition at line 922 of file dense_matrix.h.

923 {
924  for (auto i : IntRange<unsigned int>(0, this->m()))
925  (*this)(i, col) *= factor;
926 }

◆ sub_matrix()

template<typename T >
DenseMatrix< T > libMesh::DenseMatrix< T >::sub_matrix ( unsigned int  row_id,
unsigned int  row_size,
unsigned int  col_id,
unsigned int  col_size 
) const
inline

Get submatrix with the smallest row and column indices and the submatrix size.

Definition at line 849 of file dense_matrix.h.

851 {
852  libmesh_assert_less (row_id + row_size - 1, this->_m);
853  libmesh_assert_less (col_id + col_size - 1, this->_n);
854 
855  DenseMatrix<T> sub;
856  sub._m = row_size;
857  sub._n = col_size;
858  sub._val.resize(row_size * col_size);
859 
860  unsigned int end_col = this->_n - col_size - col_id;
861  unsigned int p = row_id * this->_n;
862  unsigned int q = 0;
863  for (unsigned int i=0; i<row_size; i++)
864  {
865  // skip the beginning columns
866  p += col_id;
867  for (unsigned int j=0; j<col_size; j++)
868  sub._val[q++] = _val[p++];
869  // skip the rest columns
870  p += end_col;
871  }
872 
873  return sub;
874 }

◆ svd() [1/2]

template<typename T >
void libMesh::DenseMatrix< T >::svd ( DenseVector< Real > &  sigma)

Compute the singular value decomposition of the matrix.

On exit, sigma holds all of the singular values (in descending order).

The implementation uses PETSc's interface to BLAS/LAPACK. If this is not available, this function throws an error.

Definition at line 813 of file dense_matrix_impl.h.

814 {
815  // We use the LAPACK svd implementation
816  _svd_lapack(sigma);
817 }

◆ svd() [2/2]

template<typename T >
void libMesh::DenseMatrix< T >::svd ( DenseVector< Real > &  sigma,
DenseMatrix< Number > &  U,
DenseMatrix< Number > &  VT 
)

Compute the "reduced" singular value decomposition of the matrix.

On exit, sigma holds all of the singular values (in descending order), U holds the left singular vectors, and VT holds the transpose of the right singular vectors. In the reduced SVD, U has min(m,n) columns and VT has min(m,n) rows. (In the "full" SVD, U and VT would be square.)

The implementation uses PETSc's interface to BLAS/LAPACK. If this is not available, this function throws an error.

Definition at line 821 of file dense_matrix_impl.h.

824 {
825  // We use the LAPACK svd implementation
826  _svd_lapack(sigma, U, VT);
827 }

◆ svd_solve()

template<typename T>
void libMesh::DenseMatrix< T >::svd_solve ( const DenseVector< T > &  rhs,
DenseVector< T > &  x,
Real  rcond = std::numeric_limits<Real>::epsilon() 
) const

Solve the system of equations \( A x = rhs \) for \( x \) in the least-squares sense.

\( A \) may be non-square and/or rank-deficient. You can control which singular values are treated as zero by changing the "rcond" parameter. Singular values S(i) for which S(i) <= rcond*S(1) are treated as zero for purposes of the solve. Passing a negative number for rcond forces a "machine precision" value to be used instead.

This function is marked const, since due to various implementation details, we do not need to modify the contents of A in order to compute the SVD (a copy is made internally instead).

Requires PETSc >= 3.1 since this was the first version to provide the LAPACKgelss_ wrapper.

Definition at line 832 of file dense_matrix_impl.h.

835 {
836  _svd_solve_lapack(rhs, x, rcond);
837 }

◆ swap()

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

STL-like swap method.

Definition at line 792 of file dense_matrix.h.

793 {
794  std::swap(this->_m, other_matrix._m);
795  std::swap(this->_n, other_matrix._n);
796  _val.swap(other_matrix._val);
798  _decomposition_type = other_matrix._decomposition_type;
799  other_matrix._decomposition_type = _temp;
800 }

Referenced by libMesh::EulerSolver::_general_residual(), libMesh::Euler2Solver::_general_residual(), and libMesh::NewmarkSolver::_general_residual().

◆ transpose()

template<typename T >
T libMesh::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 1106 of file dense_matrix.h.

1108 {
1109  // Implement in terms of operator()
1110  return (*this)(j,i);
1111 }

◆ vector_mult() [1/2]

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

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

Definition at line 403 of file dense_matrix_impl.h.

405 {
406  // Make sure the input sizes are compatible
407  libmesh_assert_equal_to (this->n(), arg.size());
408 
409  // Resize and clear dest.
410  // Note: DenseVector::resize() also zeros the vector.
411  dest.resize(this->m());
412 
413  // Short-circuit if the matrix is empty
414  if(this->m() == 0 || this->n() == 0)
415  return;
416 
417  if (this->use_blas_lapack)
418  this->_matvec_blas(1., 0., dest, arg);
419  else
420  {
421  const unsigned int n_rows = this->m();
422  const unsigned int n_cols = this->n();
423 
424  for (unsigned int i=0; i<n_rows; i++)
425  for (unsigned int j=0; j<n_cols; j++)
426  dest(i) += (*this)(i,j)*arg(j);
427  }
428 }

Referenced by libMesh::FEMap::compute_single_point_map(), NonlinearNeoHookeCurrentConfig::get_residual(), libMesh::TransientRBEvaluation::rb_solve(), and libMesh::TransientRBEvaluation::rb_solve_again().

◆ vector_mult() [2/2]

template<typename T>
template<typename T2 >
void libMesh::DenseMatrix< T >::vector_mult ( DenseVector< typename CompareTypes< T, T2 >::supertype > &  dest,
const DenseVector< T2 > &  arg 
) const

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

Definition at line 434 of file dense_matrix_impl.h.

436 {
437  // Make sure the input sizes are compatible
438  libmesh_assert_equal_to (this->n(), arg.size());
439 
440  // Resize and clear dest.
441  // Note: DenseVector::resize() also zeros the vector.
442  dest.resize(this->m());
443 
444  // Short-circuit if the matrix is empty
445  if (this->m() == 0 || this->n() == 0)
446  return;
447 
448  const unsigned int n_rows = this->m();
449  const unsigned int n_cols = this->n();
450 
451  for (unsigned int i=0; i<n_rows; i++)
452  for (unsigned int j=0; j<n_cols; j++)
453  dest(i) += (*this)(i,j)*arg(j);
454 }

◆ vector_mult_add() [1/2]

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

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

Definition at line 529 of file dense_matrix_impl.h.

532 {
533  // Short-circuit if the matrix is empty
534  if (this->m() == 0)
535  {
536  dest.resize(0);
537  return;
538  }
539 
540  if (this->use_blas_lapack)
541  this->_matvec_blas(factor, 1., dest, arg);
542  else
543  {
544  DenseVector<T> temp(arg.size());
545  this->vector_mult(temp, arg);
546  dest.add(factor, temp);
547  }
548 }

Referenced by libMesh::DofMap::build_constraint_matrix_and_vector().

◆ vector_mult_add() [2/2]

template<typename T>
template<typename T2 , typename T3 >
void libMesh::DenseMatrix< T >::vector_mult_add ( DenseVector< typename CompareTypes< T, typename CompareTypes< T2, T3 >::supertype >::supertype > &  dest,
const T2  factor,
const DenseVector< T3 > &  arg 
) const

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

on mixed types

Definition at line 554 of file dense_matrix_impl.h.

557 {
558  // Short-circuit if the matrix is empty
559  if (this->m() == 0)
560  {
561  dest.resize(0);
562  return;
563  }
564 
565  DenseVector<typename CompareTypes<T,T3>::supertype>
566  temp(arg.size());
567  this->vector_mult(temp, arg);
568  dest.add(factor, temp);
569 }

◆ vector_mult_transpose() [1/2]

template<typename T>
void libMesh::DenseMatrix< T >::vector_mult_transpose ( DenseVector< T > &  dest,
const DenseVector< T > &  arg 
) const

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

Definition at line 459 of file dense_matrix_impl.h.

461 {
462  // Make sure the input sizes are compatible
463  libmesh_assert_equal_to (this->m(), arg.size());
464 
465  // Resize and clear dest.
466  // Note: DenseVector::resize() also zeros the vector.
467  dest.resize(this->n());
468 
469  // Short-circuit if the matrix is empty
470  if (this->m() == 0)
471  return;
472 
473  if (this->use_blas_lapack)
474  {
475  this->_matvec_blas(1., 0., dest, arg, /*trans=*/true);
476  }
477  else
478  {
479  const unsigned int n_rows = this->m();
480  const unsigned int n_cols = this->n();
481 
482  // WORKS
483  // for (unsigned int j=0; j<n_cols; j++)
484  // for (unsigned int i=0; i<n_rows; i++)
485  // dest(j) += (*this)(i,j)*arg(i);
486 
487  // ALSO WORKS, (i,j) just swapped
488  for (unsigned int i=0; i<n_cols; i++)
489  for (unsigned int j=0; j<n_rows; j++)
490  dest(i) += (*this)(j,i)*arg(j);
491  }
492 }

◆ vector_mult_transpose() [2/2]

template<typename T>
template<typename T2 >
void libMesh::DenseMatrix< T >::vector_mult_transpose ( DenseVector< typename CompareTypes< T, T2 >::supertype > &  dest,
const DenseVector< T2 > &  arg 
) const

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

on mixed types

Definition at line 498 of file dense_matrix_impl.h.

500 {
501  // Make sure the input sizes are compatible
502  libmesh_assert_equal_to (this->m(), arg.size());
503 
504  // Resize and clear dest.
505  // Note: DenseVector::resize() also zeros the vector.
506  dest.resize(this->n());
507 
508  // Short-circuit if the matrix is empty
509  if (this->m() == 0)
510  return;
511 
512  const unsigned int n_rows = this->m();
513  const unsigned int n_cols = this->n();
514 
515  // WORKS
516  // for (unsigned int j=0; j<n_cols; j++)
517  // for (unsigned int i=0; i<n_rows; i++)
518  // dest(j) += (*this)(i,j)*arg(i);
519 
520  // ALSO WORKS, (i,j) just swapped
521  for (unsigned int i=0; i<n_cols; i++)
522  for (unsigned int j=0; j<n_rows; j++)
523  dest(i) += (*this)(j,i)*arg(j);
524 }

◆ zero()

template<typename T >
void libMesh::DenseMatrix< T >::zero ( )
inlineoverridevirtual

Set every element in the matrix to 0.

You must redefine what you mean by zeroing the matrix since it depends on how your values are stored.

Implements libMesh::DenseMatrixBase< T >.

Definition at line 838 of file dense_matrix.h.

839 {
841 
842  std::fill (_val.begin(), _val.end(), static_cast<T>(0));
843 }

Referenced by libMesh::HPCoarsenTest::add_projection(), libMesh::FEMSystem::assembly(), libMesh::FEGenericBase< FEOutputType< T >::type >::coarsened_dof_values(), libMesh::BoundaryProjectSolution::operator()(), libMesh::TransientRBEvaluation::rb_solve(), libMesh::RBEvaluation::rb_solve(), libMesh::HPCoarsenTest::select_refinement(), and DiagonalMatrixTest::testNumerics().

Member Data Documentation

◆ _decomposition_type

template<typename T>
DecompositionType libMesh::DenseMatrix< T >::_decomposition_type
private

This flag keeps track of which type of decomposition has been performed on the matrix.

Definition at line 612 of file dense_matrix.h.

◆ _m

template<typename T>
unsigned int libMesh::DenseMatrixBase< T >::_m
protectedinherited

The row dimension.

Definition at line 176 of file dense_matrix_base.h.

Referenced by libMesh::DenseMatrixBase< T >::m().

◆ _n

template<typename T>
unsigned int libMesh::DenseMatrixBase< T >::_n
protectedinherited

The column dimension.

Definition at line 181 of file dense_matrix_base.h.

Referenced by libMesh::DenseMatrixBase< T >::n().

◆ _pivots

template<typename T>
std::vector<pivot_index_t> libMesh::DenseMatrix< T >::_pivots
private

Definition at line 702 of file dense_matrix.h.

◆ _val

template<typename T>
std::vector<T> libMesh::DenseMatrix< T >::_val
private

The actual data values, stored as a 1D array.

Definition at line 562 of file dense_matrix.h.

Referenced by libMesh::DenseMatrix< Real >::get_values().

◆ use_blas_lapack

template<typename T>
bool libMesh::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 that is available on the web.

This routine is commented out since it is not really a memory- or computationally- efficient implementation. Also, you typically don't need the actual inverse for anything, and can use something like lu_solve() instead. Run-time selectable option to turn on/off BLAS support. This was primarily used for testing purposes, and could be removed...

Definition at line 555 of file dense_matrix.h.


The documentation for this class was generated from the following files:
libMesh::DenseMatrix::_svd_lapack
void _svd_lapack(DenseVector< Real > &sigma)
Computes an SVD of the matrix using the Lapack routine "getsvd".
Definition: dense_matrix_blas_lapack.C:278
libMesh::DenseMatrix::use_blas_lapack
bool use_blas_lapack
Computes the inverse of the dense matrix (assuming it is invertible) by first computing the LU decomp...
Definition: dense_matrix.h:555
libMesh::DenseMatrix::get_transpose
void get_transpose(DenseMatrix< T > &dest) const
Put the tranposed matrix into dest.
Definition: dense_matrix_impl.h:612
libMesh::DenseMatrix::LU
Definition: dense_matrix.h:606
libMesh::DenseMatrix::_pivots
std::vector< pivot_index_t > _pivots
Definition: dense_matrix.h:702
libMesh::DenseMatrix::_svd_solve_lapack
void _svd_solve_lapack(const DenseVector< T > &rhs, DenseVector< T > &x, Real rcond) const
Called by svd_solve(rhs).
Definition: dense_matrix_blas_lapack.C:532
libMesh::DenseMatrix::RIGHT_MULTIPLY_TRANSPOSE
Definition: dense_matrix.h:622
libMesh::DenseMatrixBase::multiply
static void multiply(DenseMatrixBase< T > &M1, const DenseMatrixBase< T > &M2, const DenseMatrixBase< T > &M3)
Helper function - Performs the computation M1 = M2 * M3 where: M1 = (m x n) M2 = (m x p) M3 = (p x n)
Definition: dense_matrix_base_impl.h:46
libMesh::DenseMatrix::_cholesky_back_substitute
void _cholesky_back_substitute(const DenseVector< T2 > &b, DenseVector< T2 > &x) const
Solves the equation Ax=b for the unknown value x and rhs b based on the Cholesky factorization of A.
Definition: dense_matrix_impl.h:1025
libMesh::libmesh_real
T libmesh_real(T a)
Definition: libmesh_common.h:166
libMesh::DenseMatrix::_val
std::vector< T > _val
The actual data values, stored as a 1D array.
Definition: dense_matrix.h:562
libMesh::index_range
IntRange< std::size_t > index_range(const std::vector< T > &vec)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:106
B
Definition: assembly.h:38
libMesh::DenseMatrix::_svd_helper
void _svd_helper(char JOBU, char JOBVT, std::vector< Real > &sigma_val, std::vector< Number > &U_val, std::vector< Number > &VT_val)
Helper function that actually performs the SVD.
Definition: dense_matrix_blas_lapack.C:385
libMesh::DenseMatrix::LEFT_MULTIPLY
Definition: dense_matrix.h:619
libMesh::pPS
PetscScalar * pPS(T *ptr)
Definition: petsc_macro.h:174
std::sqrt
MetaPhysicL::DualNumber< T, D > sqrt(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::DenseMatrix::_cholesky_decompose
void _cholesky_decompose()
Decomposes a symmetric positive definite matrix into a product of two lower triangular matrices accor...
Definition: dense_matrix_impl.h:979
libMesh::DenseMatrix::CHOLESKY
Definition: dense_matrix.h:606
libMesh::libmesh_conj
T libmesh_conj(T a)
Definition: libmesh_common.h:167
libMesh::DenseMatrixBase::n
unsigned int n() const
Definition: dense_matrix_base.h:109
libMesh::DenseMatrix::get_values
std::vector< T > & get_values()
Definition: dense_matrix.h:371
libMesh::DenseMatrixBase::condense
void condense(const unsigned int i, const unsigned int j, const T val, DenseVectorBase< T > &rhs)
Condense-out the (i,j) entry of the matrix, forcing it to take on the value val.
Definition: dense_matrix_base_impl.h:73
libMesh::DenseMatrix::LU_BLAS_LAPACK
Definition: dense_matrix.h:606
libMesh::DenseMatrix::NONE
Definition: dense_matrix.h:606
libMesh::DenseMatrix::LEFT_MULTIPLY_TRANSPOSE
Definition: dense_matrix.h:621
libMesh::DenseMatrix::resize
void resize(const unsigned int new_m, const unsigned int new_n)
Resize the matrix.
Definition: dense_matrix.h:822
libMesh::zero
const Number zero
.
Definition: libmesh.h:243
libMesh::DenseMatrixBase::m
unsigned int m() const
Definition: dense_matrix_base.h:104
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::DenseMatrix::vector_mult
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this) * arg.
Definition: dense_matrix_impl.h:403
std::abs
MetaPhysicL::DualNumber< T, D > abs(const MetaPhysicL::DualNumber< T, D > &in)
libMesh::DenseMatrix::_matvec_blas
void _matvec_blas(T alpha, T beta, DenseVector< T > &dest, const DenseVector< T > &arg, bool trans=false) const
Uses the BLAS GEMV function (through PETSc) to compute.
Definition: dense_matrix_blas_lapack.C:1009
libMesh::DenseMatrix::_lu_back_substitute
void _lu_back_substitute(const DenseVector< T > &b, DenseVector< T > &x) const
Solves the system Ax=b through back substitution.
Definition: dense_matrix_impl.h:684
A
static PetscErrorCode Mat * A
Definition: petscdmlibmeshimpl.C:1026
libMesh::DenseMatrixBase::_n
unsigned int _n
The column dimension.
Definition: dense_matrix_base.h:181
libMesh::DenseMatrix::zero
virtual void zero() override
Set every element in the matrix to 0.
Definition: dense_matrix.h:838
libMesh::DenseMatrix::_lu_back_substitute_lapack
void _lu_back_substitute_lapack(const DenseVector< T > &b, DenseVector< T > &x)
Companion function to _lu_decompose_lapack().
Definition: dense_matrix_blas_lapack.C:919
libMesh::DenseMatrix::_lu_decompose_lapack
void _lu_decompose_lapack()
Computes an LU factorization of the matrix using the Lapack routine "getrf".
Definition: dense_matrix_blas_lapack.C:210
swap
void swap(Iterator &lhs, Iterator &rhs)
swap, used to implement op=
Definition: variant_filter_iterator.h:478
libMesh::DenseMatrix::DecompositionType
DecompositionType
The decomposition schemes above change the entries of the matrix A.
Definition: dense_matrix.h:606
libMesh::DenseMatrix::_multiply_blas
void _multiply_blas(const DenseMatrixBase< T > &other, _BLAS_Multiply_Flag flag)
The _multiply_blas function computes A <- op(A) * op(B) using BLAS gemm function.
Definition: dense_matrix_blas_lapack.C:37
libMesh::DenseMatrix::get_principal_submatrix
void get_principal_submatrix(unsigned int sub_m, unsigned int sub_n, DenseMatrix< T > &dest) const
Put the sub_m x sub_n principal submatrix into dest.
Definition: dense_matrix_impl.h:574
libMesh::DenseMatrixBase::el
virtual T el(const unsigned int i, const unsigned int j) const =0
libMesh::DenseMatrix::_evd_lapack
void _evd_lapack(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag, DenseMatrix< T > *VL=nullptr, DenseMatrix< T > *VR=nullptr)
Computes the eigenvalues of the matrix using the Lapack routine "DGEEV".
Definition: dense_matrix_blas_lapack.C:711
libMesh::DenseMatrix::RIGHT_MULTIPLY
Definition: dense_matrix.h:620
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::DenseMatrix::_lu_decompose
void _lu_decompose()
Form the LU decomposition of the matrix.
Definition: dense_matrix_impl.h:735
libMesh::DenseMatrixBase::_m
unsigned int _m
The row dimension.
Definition: dense_matrix_base.h:176
libMesh::DenseMatrix::scale
void scale(const T factor)
Multiplies every element in the matrix by factor.
Definition: dense_matrix.h:913
libMesh::DenseMatrix::_decomposition_type
DecompositionType _decomposition_type
This flag keeps track of which type of decomposition has been performed on the matrix.
Definition: dense_matrix.h:612