有限元方法中的数值技术:Cholesky矩阵分解
计算原理
对于对称正定矩阵AAA,存在于一个实的下三角矩阵LLL,使得A=LLTA=LL^TA=LLT,若限定LLL的对角元素为正时,这种分解是唯一的。
(a11a12⋯a1na21a22⋯a2n⋮⋱an1an2⋯ann)=(l11l21l22⋯⋱ln1ln2⋯lnn)(l11l21⋯ln1l22⋯ln2⋱lnn) { \left( \begin{array} { l l l l } { a _ { 1 1 } } & { a _ { 1 2 } } & { \cdots } & { a _ { 1 n } } \\ { a _ { 2 1 } } & { a _ { 2 2 } } & { \cdots } & { a _ { 2 n } } \\ { \vdots } & & { \ddots } & \\ { a _ { n 1 } } & { a _ { n 2 } } & { \cdots } & { a _ { n n } } \end{array} \right) } = { \left( \begin{array} { l l l l } { l _ { 1 1 } } & & & \\ { l _ { 2 1 } } & { l _ { 2 2 } } & & \\ { \cdots } & & { \ddots } & \\ { l _ { n 1 } } & { l _ { n 2 } } & { \cdots } & { l _ { n n } } \end{array} \right) } { \left( \begin{array} { l l l l } { l _ { 1 1 } } & { l _ { 2 1 } } & { \cdots } & { l _ { n 1 } } \\ & { l _ { 2 2 } } & { \cdots } & { l _ { n 2 } } \\ & & { \ddots } & \\ & & & { l _ { n n } } \end{array} \right) } a11a21⋮an1a12a22an2⋯⋯⋱⋯a1na2nann=l11l21⋯ln1l22ln2⋱⋯lnnl11l21l22⋯⋯⋱ln1ln2lnn
- l11=a11l_{11} = \sqrt{a_{11}}l11=a11
- li1=ai1l11,i=2,Nl_{i1} = \frac{a_{i1}}{l_{11}}, \quad i=2,Nli1=l11ai1,i=2,N
- 对 j=2,Nj=2,Nj=2,N,做A~B处理:
A:
ljj=ajj−∑k=1j−1ljk2l_{jj} = \sqrt{a_{jj} - \sum_{k=1}^{j-1} l_{jk}^2 }ljj=ajj−k=1∑j−1ljk2
B:
lij=(aij−∑k=1j−1likljk)ljj,i=j+1,Nl_{ij} = \frac{ \left( a_{ij} - \sum_{k=1}^{j-1} l_{ik} l_{jk} \right) }{ l_{jj} }, \quad i=j+1,Nlij=ljj(aij−∑k=1j−1likljk),i=j+1,N
Fortran数值实现
subroutine cholesky(a,l,n)
! cholesky矩阵分解(只适用于对称正定矩阵)! A = L*L^Tinteger, intent(in) :: nreal*8, intent(in) :: a(n,n)real*8, intent(out) :: l(n,n)integer :: i,j,kl = 0l(1,1) = sqrt(a(1,1))l(2:,1) = a(2:,1)/l(1,1)do j = 2,ns = 0do k = 1,j-1s = s + l(j,k)**2end dol(j,j) = sqrt(a(j,j)-s)do i = j+1,ns = 0do k = 1,j-1s = s + l(i,k) * l(j,k)end dol(i,j) = (a(i,j)-s)/l(j,j)end doend do
end subroutine cholesky
数值案例
A=(233.4615113.8423256.0623145.0697113.842378.6033127.429895.3089256.0623127.4298281.4721164.8676145.069795.3089164.8676181.2339) \mathbf{A} = \left( \begin{array}{cccc} 233.4615 & 113.8423 & 256.0623 & 145.0697 \\ 113.8423 & 78.6033 & 127.4298 & 95.3089 \\ 256.0623 & 127.4298 & 281.4721 & 164.8676 \\ 145.0697 & 95.3089 & 164.8676 & 181.2339 \end{array} \right) A=233.4615113.8423256.0623145.0697113.842378.6033127.429895.3089256.0623127.4298281.4721164.8676145.069795.3089164.8676181.2339
主程序:
program mainimplicit noneinteger, parameter :: n = 4real*8 :: a(n,n),l(n,n)integer :: i, ja = reshape([ &233.4615d0, 113.8423d0, 256.0623d0, 145.0697d0, &113.8423d0, 78.6033d0, 127.4298d0, 95.3089d0, &256.0623d0, 127.4298d0, 281.4721d0, 164.8676d0, &145.0697d0, 95.3089d0, 164.8676d0, 181.2339d0 &], shape(a), order=[2,1])call cholesky(a, l, n)print *, "Lower Triangular Matrix L from Cholesky decomposition:"do i = 1, nwrite(*, 100) (l(i,j), j = 1, n)end do100 format(4F12.6)
end program main
输出:
Lower Triangular Matrix L from Cholesky decomposition:15.279447 0.000000 0.000000 0.0000007.450682 4.805272 0.000000 0.00000016.758610 0.534147 0.579450 0.0000009.494434 5.112904 5.217081 6.142468
求解矩阵方程
对于Ax=b\mathbf { A x } = \mathbf { b }Ax=b,进行cholesky分解:
LLTx=b,等价于{Ly=bLTx=y \mathbf { L } \mathbf { L } ^ { T } \mathbf { x } = \mathbf { b },等价于\left\{ \begin{array} { l l } { \mathbf { L } \mathbf { y } = \mathbf { b } } \\ { \mathbf { L } ^ { \mathrm { T } } \mathbf { x } = \mathbf { y } } \end{array} \right. LLTx=b,等价于{Ly=bLTx=y
对于:
A=(4−11−14.252.7512.753.5),b=(467.25) \mathbf { A } = { \left( \begin{array} { l l l } { 4 } & { - 1 } & { 1 } \\ { - 1 } & { 4 . 2 5 } & { 2 . 7 5 } \\ { 1 } & { 2 . 7 5 } & { 3 . 5 } \end{array} \right) } , \mathbf { b } = { \left( \begin{array} { l } { 4 } \\ { 6 } \\ { 7 . 2 5 } \end{array} \right) } A=4−11−14.252.7512.753.5,b=467.25
program mainimplicit noneinteger, parameter :: n = 3real*8 :: a(n,n), l(n,n), b(n), x(n), y(n)integer :: ia = reshape([ &4.0d0, -1.0d0, 1.0d0, &-1.0d0, 4.25d0, 2.75d0, &1.0d0, 2.75d0, 3.5d0 &], shape(a), order=[2,1])b = [4.0d0, 6.0d0, 7.25d0]call cholesky(a, l, n)! 解 Ly = bcall lowtri(l, b, y, n)! 解 L^T x = ycall uptri(transpose(l), y, x, n)print *, "Solution vector x:"write(*, 100) x100 format(3F12.6)
end program main
输出:
Solution vector x:1.000000 1.000000 1.000000
注意:子程序中默认:
implicit real*8(a-z)
参考文献
- 宋叶志,茅永兴,赵秀杰.Fortran 95/2003科学计算与工程[M].清华大学出版社,2011.