19#ifndef LIBMESH_DENSE_MATRIX_IMPL_H
20#define LIBMESH_DENSE_MATRIX_IMPL_H
27#include "libmesh/dense_matrix.h"
28#include "libmesh/dense_vector.h"
29#include "libmesh/int_range.h"
30#include "libmesh/libmesh.h"
32#ifdef LIBMESH_HAVE_METAPHYSICL
33#include "metaphysicl/dualnumber_decl.h"
47 if (this->use_blas_lapack)
48 this->_multiply_blas(M2, LEFT_MULTIPLY);
61 this->resize (M2.
m(), M3.
n());
64 this->multiply(*
this, M2, M3);
84 this->resize (M2.
m(), M3.
n());
87 this->multiply(*
this, M2, M3);
95 if (this->use_blas_lapack)
96 this->_multiply_blas(A, LEFT_MULTIPLY_TRANSPOSE);
98 this->_left_multiply_transpose(A);
106 this->_left_multiply_transpose(A);
125 const unsigned int n_rows = A.
m();
126 const unsigned int n_cols = A.
n();
129 this->resize(n_cols,n_cols);
132 for (
unsigned int i=0; i<n_cols; ++i)
133 for (
unsigned int j=0; j<=i; ++j)
134 for (
unsigned int k=0; k<n_rows; ++k)
135 (*
this)(i,j) +=
B(k,i)*
B(k,j);
138 for (
unsigned int i=0; i<n_cols; ++i)
139 for (
unsigned int j=i+1; j<n_cols; ++j)
140 (*
this)(i,j) = (*
this)(j,i);
147 this->resize (A.
n(),
B.n());
149 libmesh_assert_equal_to (A.
m(),
B.m());
150 libmesh_assert_equal_to (this->m(), A.
n());
151 libmesh_assert_equal_to (this->n(),
B.n());
153 const unsigned int m_s = A.
n();
154 const unsigned int p_s = A.
m();
155 const unsigned int n_s = this->n();
160 for (
unsigned int i=0; i<m_s; i++)
161 for (
unsigned int k=0; k<p_s; k++)
163 for (
unsigned int j=0; j<n_s; j++)
173 if (this->use_blas_lapack)
174 this->_multiply_blas(M3, RIGHT_MULTIPLY);
187 this->resize (M2.m(), M3.
n());
189 this->multiply(*
this, M2, M3);
209 this->resize (M2.m(), M3.
n());
211 this->multiply(*
this, M2, M3);
220 if (this->use_blas_lapack)
221 this->_multiply_blas(
B, RIGHT_MULTIPLY_TRANSPOSE);
223 this->_right_multiply_transpose(
B);
232 this->_right_multiply_transpose(
B);
252 const unsigned int n_rows =
B.m();
253 const unsigned int n_cols =
B.n();
256 this->resize(n_rows,n_rows);
259 for (
unsigned int i=0; i<n_rows; ++i)
260 for (
unsigned int j=0; j<=i; ++j)
261 for (
unsigned int k=0; k<n_cols; ++k)
262 (*
this)(i,j) += A(i,k)*A(j,k);
265 for (
unsigned int i=0; i<n_rows; ++i)
266 for (
unsigned int j=i+1; j<n_rows; ++j)
267 (*
this)(i,j) = (*
this)(j,i);
274 this->resize (A.
m(),
B.m());
276 libmesh_assert_equal_to (A.
n(),
B.n());
277 libmesh_assert_equal_to (this->m(), A.
m());
278 libmesh_assert_equal_to (this->n(),
B.m());
280 const unsigned int m_s = A.
m();
281 const unsigned int p_s = A.
n();
282 const unsigned int n_s = this->n();
287 for (
unsigned int j=0; j<n_s; j++)
288 for (
unsigned int k=0; k<p_s; k++)
289 if (
B.transpose(k,j) != 0.)
290 for (
unsigned int i=0; i<m_s; i++)
291 (*
this)(i,j) += A(i,k)*
B.transpose(k,j);
303 libmesh_assert_equal_to (this->n(), arg.
size());
310 if(this->m() == 0 || this->n() == 0)
313 if (this->use_blas_lapack)
314 this->_matvec_blas(1., 0., dest, arg);
317 const unsigned int n_rows = this->m();
318 const unsigned int n_cols = this->n();
320 for (
unsigned int i=0; i<n_rows; i++)
321 for (
unsigned int j=0; j<n_cols; j++)
322 dest(i) += (*this)(i,j)*arg(j);
334 libmesh_assert_equal_to (this->n(), arg.
size());
338 dest.resize(this->m());
341 if (this->m() == 0 || this->n() == 0)
344 const unsigned int n_rows = this->m();
345 const unsigned int n_cols = this->n();
347 for (
unsigned int i=0; i<n_rows; i++)
348 for (
unsigned int j=0; j<n_cols; j++)
349 dest(i) += (*this)(i,j)*arg(j);
359 libmesh_assert_equal_to (this->m(), arg.
size());
369 if (this->use_blas_lapack)
371 this->_matvec_blas(1., 0., dest, arg,
true);
375 const unsigned int n_rows = this->m();
376 const unsigned int n_cols = this->n();
384 for (
unsigned int i=0; i<n_cols; i++)
385 for (
unsigned int j=0; j<n_rows; j++)
386 dest(i) += (*this)(j,i)*arg(j);
398 libmesh_assert_equal_to (this->m(), arg.
size());
408 const unsigned int n_rows = this->m();
409 const unsigned int n_cols = this->n();
417 for (
unsigned int i=0; i<n_cols; i++)
418 for (
unsigned int j=0; j<n_rows; j++)
419 dest(i) += (*this)(j,i)*arg(j);
436 if (this->use_blas_lapack)
437 this->_matvec_blas(factor, 1., dest, arg);
441 this->vector_mult(temp, arg);
442 dest.
add(factor, temp);
449template<
typename T2,
typename T3>
463 this->vector_mult(temp, arg);
476 dest.
resize(sub_m, sub_n);
477 for (
unsigned int i=0; i<sub_m; i++)
478 for (
unsigned int j=0; j<sub_n; j++)
479 dest(i,j) = (*this)(i,j);
488 const unsigned int m = a.
size();
489 const unsigned int n =
b.size();
492 for (
unsigned int i = 0; i < m; ++i)
493 for (
unsigned int j = 0; j < n; ++j)
502 get_principal_submatrix(sub_m, sub_m, dest);
510 dest.
resize(this->n(), this->m());
514 dest(i,j) = (*this)(j,i);
535 libmesh_assert_equal_to (this->m(), this->n());
537 switch(this->_decomposition_type)
541 if (this->use_blas_lapack)
542 this->_lu_decompose_lapack();
544 this->_lu_decompose ();
551 if (this->use_blas_lapack)
554 libmesh_fallthrough();
559 if (!(this->use_blas_lapack))
562 libmesh_fallthrough();
565 libmesh_error_msg(
"Error! This matrix already has a different decomposition...");
568 if (this->use_blas_lapack)
569 this->_lu_back_substitute_lapack (
b, x);
571 this->_lu_back_substitute (
b, x);
586 libmesh_assert_equal_to (this->m(), n_cols);
587 libmesh_assert_equal_to (this->m(),
b.size());
599 for (
unsigned int i=0; i<n_cols; ++i)
603 std::swap( z(i), z(_pivots[i]) );
607 for (
unsigned int j=0; j<i; ++j)
614 const unsigned int last_row = n_cols-1;
616 for (
int i=last_row; i>=0; --i)
618 for (
int j=i+1; j<static_cast<int>(n_cols); ++j)
637 libmesh_assert_equal_to (this->_decomposition_type, NONE);
648 for (
unsigned int i=0; i<n_rows; ++i)
654 auto the_max = abs( A(i,i) );
655 for (
unsigned int j=i+1; j<n_rows; ++j)
657 auto candidate_max = abs( A(j,i) );
658 if (the_max < candidate_max)
660 the_max = candidate_max;
670 if (_pivots[i] !=
static_cast<pivot_index_t
>(i))
672 for (
unsigned int j=0; j<n_rows; ++j)
673 std::swap( A(i,j), A(_pivots[i], j) );
678 libmesh_degenerate_mapping_msg (
"Matrix A is singular!");
682 const T diag_inv = 1. / A(i,i);
683 for (
unsigned int j=i+1; j<n_rows; ++j)
697 for (
unsigned int row=i+1; row<n_rows; ++row)
698 for (
unsigned int col=i+1; col<n_rows; ++col)
699 A(row,col) -= A(row,i) * A(i,col);
704 this->_decomposition_type = LU;
723 _svd_lapack(sigma, U, VT);
733 _svd_solve_lapack(rhs, x, rcond);
743 _evd_lapack(lambda_real, lambda_imag);
754 _evd_lapack(lambda_real, lambda_imag, &VL,
nullptr);
765 _evd_lapack(lambda_real, lambda_imag,
nullptr, &VR);
777 _evd_lapack(lambda_real, lambda_imag, &VL, &VR);
785 switch(this->_decomposition_type)
792 if (this->use_blas_lapack)
793 this->_lu_decompose_lapack();
795 this->_lu_decompose ();
804 libmesh_error_msg(
"Error! Can't compute the determinant under the current decomposition.");
815 unsigned int n_interchanges = 0;
818 if (this->_decomposition_type==LU)
823 if (this->_decomposition_type==LU_BLAS_LAPACK)
827 determinant *= (*this)(i,i);
832 Real sign = n_interchanges % 2 == 0 ? 1. : -1.;
834 return sign*determinant;
843template <
typename T2>
848 switch(this->_decomposition_type)
852 this->_cholesky_decompose ();
863 libmesh_error_msg(
"Error! This matrix already has a different decomposition...");
867 this->_cholesky_back_substitute (
b, x);
882 libmesh_assert_equal_to (this->_decomposition_type, NONE);
890 libmesh_assert_equal_to (n_rows, n_cols);
895 for (
unsigned int i=0; i<n_rows; ++i)
897 for (
unsigned int j=i; j<n_cols; ++j)
899 for (
unsigned int k=0; k<i; ++k)
900 A(i,j) -= A(i,k) * A(j,k);
904#ifndef LIBMESH_USE_COMPLEX_NUMBERS
905 libmesh_error_msg_if(A(i,j) <= 0.0,
906 "Error! Can only use Cholesky decomposition with symmetric positive definite matrices.");
909 A(i,i) = sqrt(A(i,j));
912 A(j,i) = A(i,j) / A(i,i);
917 this->_decomposition_type = CHOLESKY;
923template <
typename T2>
933 libmesh_assert_equal_to (n_rows, n_cols);
942 for (
unsigned int i=0; i<n_cols; ++i)
946 for (
unsigned int k=0; k<i; ++k)
949 x(i) = temp / A(i,i);
953 for (
unsigned int i=0; i<n_cols; ++i)
955 const unsigned int ib = (n_cols-1)-i;
957 for (
unsigned int k=(ib+1); k<n_cols; ++k)
958 x(ib) -= A(k,ib) * x(k);
Defines an abstract dense matrix base class for use in Finite Element-type computations.
Defines a dense matrix for use in Finite Element-type computations.
void _cholesky_decompose()
Decomposes a symmetric positive definite matrix into a product of two lower triangular matrices accor...
void _lu_decompose()
Form the LU decomposition of the matrix.
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,...
void _lu_back_substitute(const DenseVector< T > &b, DenseVector< T > &x) const
Solves the system Ax=b through back substitution.
void right_multiply_transpose(const DenseMatrix< T > &A)
Right multiplies by the transpose of the matrix A.
void _left_multiply_transpose(const DenseMatrix< T2 > &A)
Left multiplies by the transpose of the matrix A which may contain a different numerical type.
void _right_multiply_transpose(const DenseMatrix< T2 > &A)
Right multiplies by the transpose of the matrix A which may contain a different numerical type.
void svd_solve(const DenseVector< T > &rhs, DenseVector< T > &x, Real rcond=std::numeric_limits< Real >::epsilon()) const
Solve the system of equations for in the least-squares sense.
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this) * arg.
void cholesky_solve(const DenseVector< T2 > &b, DenseVector< T2 > &x)
For symmetric positive definite (SPD) matrices.
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.
void resize(const unsigned int new_m, const unsigned int new_n)
Resizes the matrix to the specified size and calls zero().
void svd(DenseVector< Real > &sigma)
Compute the singular value decomposition of the matrix.
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
Solve the system Ax=b given the input vector b.
virtual void right_multiply(const DenseMatrixBase< T > &M2) override final
Performs the operation: (*this) <- (*this) * M3.
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.
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,...
void get_transpose(DenseMatrix< T > &dest) const
Put the tranposed matrix into dest.
void vector_mult_transpose(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this)^T * arg.
T transpose(const unsigned int i, const unsigned int j) const
virtual void left_multiply(const DenseMatrixBase< T > &M2) override final
Performs the operation: (*this) <- M2 * (*this)
void outer_product(const DenseVector< T > &a, const DenseVector< T > &b)
Computes the outer (dyadic) product of two vectors and stores in (*this).
PetscBLASInt pivot_index_t
Array used to store pivot indices.
void evd(DenseVector< T > &lambda_real, DenseVector< T > &lambda_imag)
Compute the eigenvalues (both real and imaginary parts) of a general matrix.
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...
void left_multiply_transpose(const DenseMatrix< T > &A)
Left multiplies by the transpose of the matrix A.
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.
Defines a dense vector for use in Finite Element-type computations.
void resize(const unsigned int n)
Resize the vector.
std::enable_if< ScalarTraits< T2 >::value, void >::type add(const T2 factor, const DenseVector< T3 > &vec)
Adds factor times vec to this vector.
virtual unsigned int size() const override final
The libMesh namespace provides an interface to certain functionality in the library.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...