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"
53 if (this->use_blas_lapack)
54 this->_multiply_blas(M2, LEFT_MULTIPLY);
61 this->resize(M2.
m(), M3.
n());
64 this->multiply(*
this, M2, M3);
82 this->resize(M2.
m(), M3.
n());
85 this->multiply(*
this, M2, M3);
98 if (this->use_blas_lapack)
99 this->_multiply_blas(A, LEFT_MULTIPLY_TRANSPOSE);
101 this->_left_multiply_transpose(A);
110 template<
typename T2>
113 this->_left_multiply_transpose(A);
124 template<
typename T2>
138 const unsigned int n_rows = A.
m();
139 const unsigned int n_cols = A.
n();
142 this->resize(n_cols, n_cols);
145 for (
unsigned int i = 0; i < n_cols; ++i)
146 for (
unsigned int j = 0; j <= i; ++j)
147 for (
unsigned int k = 0; k < n_rows; ++k)
148 (*
this)(i, j) += B(k, i) * B(k, j);
151 for (
unsigned int i = 0; i < n_cols; ++i)
152 for (
unsigned int j = i + 1; j < n_cols; ++j)
153 (*
this)(i, j) = (*
this)(j, i);
159 this->resize(A.
n(), B.
n());
161 libmesh_assert_equal_to(A.
m(), B.
m());
162 libmesh_assert_equal_to(this->m(), A.
n());
163 libmesh_assert_equal_to(this->n(), B.
n());
165 const unsigned int m_s = A.
n();
166 const unsigned int p_s = A.
m();
167 const unsigned int n_s = this->n();
172 for (
unsigned int i = 0; i < m_s; i++)
173 for (
unsigned int k = 0; k < p_s; k++)
175 for (
unsigned int j = 0; j < n_s; j++)
176 (*
this)(i, j) += A.
transpose(i, k) * B(k, j);
190 if (this->use_blas_lapack)
191 this->_multiply_blas(M3, RIGHT_MULTIPLY);
198 this->resize(M2.
m(), M3.
n());
200 this->multiply(*
this, M2, M3);
212 template<
typename T2>
219 this->resize(M2.
m(), M3.
n());
221 this->multiply(*
this, M2, M3);
234 if (this->use_blas_lapack)
235 this->_multiply_blas(B, RIGHT_MULTIPLY_TRANSPOSE);
237 this->_right_multiply_transpose(B);
246 template<
typename T2>
249 this->_right_multiply_transpose(B);
260 template<
typename T2>
274 const unsigned int n_rows = B.
m();
275 const unsigned int n_cols = B.
n();
278 this->resize(n_rows, n_rows);
281 for (
unsigned int i = 0; i < n_rows; ++i)
282 for (
unsigned int j = 0; j <= i; ++j)
283 for (
unsigned int k = 0; k < n_cols; ++k)
284 (*
this)(i, j) += A(i, k) * A(j, k);
287 for (
unsigned int i = 0; i < n_rows; ++i)
288 for (
unsigned int j = i + 1; j < n_rows; ++j)
289 (*
this)(i, j) = (*
this)(j, i);
295 this->resize(A.
m(), B.
m());
297 libmesh_assert_equal_to(A.
n(), B.
n());
298 libmesh_assert_equal_to(this->m(), A.
m());
299 libmesh_assert_equal_to(this->n(), B.
m());
301 const unsigned int m_s = A.
m();
302 const unsigned int p_s = A.
n();
303 const unsigned int n_s = this->n();
307 for (
unsigned int j = 0; j < n_s; j++)
308 for (
unsigned int k = 0; k < p_s; k++)
310 for (
unsigned int i = 0; i < m_s; i++)
311 (*
this)(i, j) += A(i, k) * B.
transpose(k, j);
329 libmesh_assert_equal_to(this->n(), arg.
size());
336 if (this->m() == 0 || this->n() == 0)
339 if (this->use_blas_lapack)
340 this->_matvec_blas(1., 0., dest, arg);
343 const unsigned int n_rows = this->m();
344 const unsigned int n_cols = this->n();
346 for (
unsigned int i = 0; i < n_rows; i++)
347 for (
unsigned int j = 0; j < n_cols; j++)
348 dest(i) += (*this)(i, j) * arg(j);
359 template<
typename T2>
364 libmesh_assert_equal_to(this->n(), arg.
size());
368 dest.resize(this->m());
371 if (this->m() == 0 || this->n() == 0)
374 const unsigned int n_rows = this->m();
375 const unsigned int n_cols = this->n();
377 for (
unsigned int i = 0; i < n_rows; i++)
378 for (
unsigned int j = 0; j < n_cols; j++)
379 dest(i) += (*this)(i, j) * arg(j);
396 libmesh_assert_equal_to(this->m(), arg.
size());
406 if (this->use_blas_lapack)
408 this->_matvec_blas(1., 0., dest, arg,
true);
412 const unsigned int n_rows = this->m();
413 const unsigned int n_cols = this->n();
421 for (
unsigned int i = 0; i < n_cols; i++)
422 for (
unsigned int j = 0; j < n_rows; j++)
423 dest(i) += (*this)(j, i) * arg(j);
434 template<
typename T2>
439 libmesh_assert_equal_to(this->m(), arg.
size());
443 dest.resize(this->n());
449 const unsigned int n_rows = this->m();
450 const unsigned int n_cols = this->n();
458 for (
unsigned int i = 0; i < n_cols; i++)
459 for (
unsigned int j = 0; j < n_rows; j++)
460 dest(i) += (*this)(j, i) * arg(j);
484 if (this->use_blas_lapack)
485 this->_matvec_blas(factor, 1., dest, arg);
489 this->vector_mult(temp, arg);
490 dest.
add(factor, temp);
504 template<
typename T2,
typename T3>
517 this->vector_mult(temp, arg);
518 dest.add(factor, temp);
533 libmesh_assert((sub_m <= this->m()) && (sub_n <= this->n()));
535 dest.
resize(sub_m, sub_n);
536 for (
unsigned int i = 0; i < sub_m; i++)
537 for (
unsigned int j = 0; j < sub_n; j++)
538 dest(i, j) = (*this)(i, j);
551 const unsigned int m = a.
size();
552 const unsigned int n = b.
size();
555 for (
unsigned int i = 0; i < m; ++i)
556 for (
unsigned int j = 0; j < n; ++j)
569 get_principal_submatrix(sub_m, sub_m, dest);
580 dest.
resize(this->n(), this->m());
582 for (
auto i : make_range(dest.
m()))
583 for (
auto j : make_range(dest.
n()))
584 dest(i, j) = (*this)(j, i);
610 libmesh_assert_equal_to(this->m(), this->n());
612 switch (this->_decomposition_type)
616 if (this->use_blas_lapack)
617 this->_lu_decompose_lapack();
619 this->_lu_decompose();
626 if (this->use_blas_lapack)
629 libmesh_fallthrough();
634 if (!(this->use_blas_lapack))
637 libmesh_fallthrough();
640 libmesh_error_msg(
"Error! This matrix already has a different decomposition...");
643 if (this->use_blas_lapack)
644 this->_lu_back_substitute_lapack(b, x);
646 this->_lu_back_substitute(b, x);
658 const unsigned int n_cols = this->n();
660 libmesh_assert_equal_to(this->m(), n_cols);
661 libmesh_assert_equal_to(this->m(), b.
size());
672 for (
unsigned int i = 0; i < n_cols; ++i)
675 if (_pivots[i] != static_cast<pivot_index_t>(i))
676 std::swap(z(i), z(_pivots[i]));
680 for (
unsigned int j = 0; j < i; ++j)
681 x(i) -= A(i, j) * x(j);
687 const unsigned int last_row = n_cols - 1;
689 for (
int i = last_row; i >= 0; --i)
691 for (
int j = i + 1; j < static_cast<int>(n_cols); ++j)
692 x(i) -= A(i, j) * x(j);
703 libmesh_assert_equal_to(this->_decomposition_type, NONE);
706 const unsigned int n_rows = this->m();
713 for (
unsigned int i = 0; i < n_rows; ++i)
720 for (
unsigned int j = i + 1; j < n_rows; ++j)
722 auto candidate_max =
std::abs(A(j, i));
723 if (the_max < candidate_max)
725 the_max = candidate_max;
732 if (_pivots[i] != static_cast<pivot_index_t>(i))
734 for (
unsigned int j = 0; j < n_rows; ++j)
735 std::swap(A(i, j), A(_pivots[i], j));
739 libmesh_error_msg_if(A(i, i) ==
libMesh::zero,
"Matrix A is singular!");
743 const T diag_inv = 1. / A(i, i);
744 for (
unsigned int j = i + 1; j < n_rows; ++j)
753 for (
unsigned int row = i + 1; row < n_rows; ++row)
754 for (
unsigned int col = i + 1; col < n_rows; ++col)
755 A(row, col) -= A(row, i) * A(i, col);
759 this->_decomposition_type = LU;
787 _svd_lapack(sigma, U, VT);
802 template <
typename T>
803 template <
typename T2>
807 switch (this->_decomposition_type)
811 this->_cholesky_decompose();
822 libmesh_error_msg(
"Error! This matrix already has a different decomposition...");
826 this->_cholesky_back_substitute(b, x);
834 template <
typename T>
838 libmesh_assert_equal_to(this->_decomposition_type, NONE);
841 const unsigned int n_rows = this->m();
842 const unsigned int n_cols = this->n();
845 libmesh_assert_equal_to(n_rows, n_cols);
850 for (
unsigned int i = 0; i < n_rows; ++i)
852 for (
unsigned int j = i; j < n_cols; ++j)
854 for (
unsigned int k = 0; k < i; ++k)
855 A(i, j) -= A(i, k) * A(j, k);
859 #ifndef LIBMESH_USE_COMPLEX_NUMBERS
860 libmesh_error_msg_if(A(i, j) <= 0.0,
861 "Error! Can only use Cholesky decomposition with symmetric positive definite matrices.");
867 A(j, i) = A(i, j) / A(i, i);
872 this->_decomposition_type = CHOLESKY;
883 template <
typename T>
884 template <
typename T2>
889 libmesh_assert_equal_to(this->m(), this->n());
892 const unsigned int n_rows = this->m();
893 const unsigned int n_cols = this->n();
902 for (
unsigned int i = 0; i < n_cols; ++i)
906 for (
unsigned int k = 0; k < i; ++k)
907 temp -= A(i, k) * x(k);
909 x(i) = temp / A(i, i);
913 for (
unsigned int i = 0; i < n_cols; ++i)
915 const unsigned int ib = (n_cols - 1) - i;
917 for (
unsigned int k = (ib + 1); k < n_cols; ++k)
918 x(ib) -= A(k, ib) * x(k);
977 #endif // LIBMESH_DENSE_MATRIX_IMPL_H
void _lu_back_substitute(const DenseVector< T > &b, DenseVector< T > &x) const
通过回代步骤解方程Ax=b。此函数是私有的,因为它仅在lu_solve(...)函数的实现部分中被调用。
boostcopy::enable_if_c< ScalarTraits< T2 >::value, void >::type add(const T2 factor, const DenseVector< T3 > &vec)
将 factor 乘以 vec 添加到该向量。这应该仅在 T += T2 * T3 是有效的 C++ 且 T2 是标量的情况下起作用。 返回类型是 void。
unsigned int n() const
返回矩阵的列维度。
virtual void left_multiply(const DenseMatrixBase< T > &M2) overridefinal
左乘以矩阵 M2。
void vector_mult_transpose(DenseVector< T > &dest, const DenseVector< T > &arg) const
执行矩阵-向量乘法,dest := (*this)^T * arg。
void resize(const unsigned int n)
调整向量的大小。将所有元素设置为0。
void _cholesky_back_substitute(const DenseVector< T2 > &b, DenseVector< T2 > &x) const
根据矩阵A的Cholesky分解解方程Ax=b,得到未知值x和rhs b。
void get_transpose(DenseMatrix< T > &dest) const
将转置矩阵存储在 dest 中。
ADRealEigenVector< T, D, asd > sqrt(const ADRealEigenVector< T, D, asd > &)
计算自动微分实数向量的平方根。
void outer_product(const DenseVector< T > &a, const DenseVector< T > &b)
计算两个向量的外积并将结果存储在 (*this) 中。
ADRealEigenVector< T, D, asd > abs(const ADRealEigenVector< T, D, asd > &)
计算自动微分实数向量的绝对值。
unsigned int m() const
返回矩阵的行维度。
void svd(DenseVector< Real > &sigma)
计算矩阵的奇异值分解(SVD)。 在退出时,sigma包含所有奇异值(按降序排列)。
void _lu_decompose()
形成矩阵的LU分解。此函数是私有的,因为它仅在lu_solve(...)函数的实现部分中被调用。
void vector_mult_add(DenseVector< T > &dest, const T factor, const DenseVector< T > &arg) const
执行缩放矩阵-向量乘法,结果存储在 dest 中。 dest += factor * (*this) * arg.
T transpose(const unsigned int i, const unsigned int j) const
返回转置矩阵的 (i, j) 元素。
void get_principal_submatrix(unsigned int sub_m, unsigned int sub_n, DenseMatrix< T > &dest) const
将 sub_m x sub_n 的主子矩阵放入 dest 中。
virtual void right_multiply(const DenseMatrixBase< T > &M2) overridefinal
右乘以矩阵 M2。
void _cholesky_decompose()
将对称正定矩阵分解为两个下三角矩阵的乘积,即A = LL^T。
void right_multiply_transpose(const DenseMatrix< T > &A)
用矩阵 A 的转置右乘。
void lu_solve(const DenseVector< T > &b, DenseVector< T > &x)
解方程组 给定输入向量 b。
void left_multiply_transpose(const DenseMatrix< T > &A)
用矩阵 A 的转置左乘。
void _left_multiply_transpose(const DenseMatrix< T2 > &A)
由矩阵 A 的转置左乘,该矩阵可能包含不同的数值类型。
void resize(const unsigned int new_m, const unsigned int new_n)
调整矩阵的大小,并调用 zero() 方法。
void cholesky_solve(const DenseVector< T2 > &b, DenseVector< T2 > &x)
对于对称正定矩阵(SPD),进行Cholesky分解。 分解为 A = L L^T,比标准LU分解大约快两倍。 因此,如果事先知道矩阵是SPD,则可以使用此方法。如果矩阵不是SPD,则会生成错误。 Ch...
定义用于有限元计算的稠密向量类。该类基本上是为了补充 DenseMatrix 类而设计的。 它相对于 std::vector 具有额外的功能,使其在有限元中特别有用,特别是对于方程组。 所有重写的虚拟函...
void _right_multiply_transpose(const DenseMatrix< T2 > &A)
由矩阵 A 的转置右乘,该矩阵可能包含不同的数值类型。
为有限元类型的计算定义了一个抽象的稠密矩阵基类。例如 DenseSubMatrices 可以从这个类派生出来。
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
执行矩阵-向量乘法,dest := (*this) * arg。
定义用于有限元类型计算的密集矩阵。 用于在求和成全局矩阵之前存储单元刚度矩阵。所有被覆盖的虚函数都记录在dense_matrix_base.h中。
virtual unsigned int size() const overridefinal