跳转至

Doolittle矩阵分解

约 450 个字 102 行代码 预计阅读时间 3 分钟

算法原理

L、U分解后:

\[ \mathbf{L}=\left( \begin{array}{l} 1& 0& 0& 0\\ l_{21}& 1& 0& 0\\ \vdots& ...& \ddots& 0\\ l_{n1}& l_{n2}& \cdots& 1\\ \end{array} \right) \]
\[ \mathbf{U}=\left( \begin{array}{l} u_{11}& u_{12}& \cdots& u_{1n}\\ 0& u_{22}& \cdots& u_{2n}\\ 0& 0& \ddots& \vdots\\ 0& 0& 0& u_{nn}\\ \end{array} \right) \]
  • 计算\(LU\)分解中的\(U\)的第一行元素和\(L\)的第一列
\[ \begin{array} { l } { { u _ { 1 i } = a _ { 1 i } , i = 1 , \cdots , n } } \\ { { l _ { j 1 } = \displaystyle \frac { a _ { j 1 } } { u _ { 1 1 } } , j = 1 , \cdots , n } } \end{array} \]
  • 对于\(k=2,···,n\)计算以及\(U\)的第\(k\)行元素:
\[ u _ { k j } = a _ { k j } - \sum _ { m = 1 } ^ { k - 1 } l _ { k m } u _ { m j } \, , \quad j = k , k + 1 , \cdots , n \]
  • 以及\(L\)的第\(k\)列元素:
\[ l _ { i k } = \frac { a _ { i k } - \sum _ { m = 1 } ^ { k - 1 } l _ { i m } u _ { m k } } { u _ { k k } } , \quad i = k + 1 , \cdots , n \]

Fortran数值实现

subroutine doolittle(a,l,u,n)
! doolittle矩阵分解
    ! A = LU
    integer, intent(in) :: n
    real*8, intent(in) :: a(n,n)
    real*8, intent(out) :: l(n,n),u(n,n)

    integer :: i,j,k,m

    ! U的第一行和L的第一列
    u(1,:) = a(1,:)
    l(:,1) = a(:,1)/u(1,1)

    do k = 2,n
        l(k,k) = 1
        do j = k,n
            s = 0
            do m = 1,k-1
                s = s + l(k,m) * u(m,j)
            end do
            u(k,j) = a(k,j) - s
        end do
        do i = k+1,n
            s = 0
            do m = 1,k-1
                s = s + l(i,m) * u(m,k)
            end do
            l(i,k) = (a(i,k)-s)/u(k,k)
        end do
    end do
end subroutine doolittle

数值案例

\[ \begin{array} { r } { \mathbf { A } = \left( \begin{array} { c c c } { 6 } & { 3 } & { - 8 } \\ { 1 5 } & { 5 } & { 2 } \\ { 2 } & { 2 } & { 7 } \end{array} \right) } \end{array} \]

主程序:

program main
    implicit none
    integer, parameter :: n = 3
    real*8 :: a(n,n), l(n,n), u(n,n)
    integer :: i, j

    a = reshape([ 6.0d0, 3.0d0, -8.0d0, &
                  15.0d0, 5.0d0, 2.0d0, &
                  2.0d0, 0.0d0, 7.0d0  &
                ], shape(a), order=[2,1])

    print *, "Original Matrix A:"
    do i = 1, n
        write(*, 100) (a(i,j), j = 1, n)
    end do
    print *

    call doolittle(a, l, u, n)

    print *, "Lower Triangular Matrix L:"
    do i = 1, n
        write(*, 100) (l(i,j), j = 1, n)
    end do
    print *

    print *, "Upper Triangular Matrix U:"
    do i = 1, n
        write(*, 100) (u(i,j), j = 1, n)
    end do

100 format(3F12.6)
end program main

输出:

 Lower Triangular Matrix L:
    1.000000    0.000000    0.000000
    2.500000    1.000000    0.000000
    0.333333    0.400000    1.000000

 Upper Triangular Matrix U:
    6.000000    3.000000   -8.000000
    0.000000   -2.500000   22.000000
    0.000000    0.000000    0.866667

求解矩阵方程

对于对于\(\mathbf { A x } = \mathbf { b }\),进行Doolittle分解:\(\mathbf { L U x } = \mathbf { b }\)

分两步求解:

  1. \(\mathbf { L } \mathbf { y } = \mathbf { b }\)
  2. \(\mathbf { U } \mathbf { x } = \mathbf { y }\)
\[ \mathbf { A } = \left( \begin{array} { c c c c } { 6 . 5 5 7 4 } & { 6 . 7 8 7 4 } & { 6 . 5 5 4 8 } & { 2 . 7 6 9 2 } \\ { 0 . 3 5 7 1 } & { 7 . 5 7 7 4 } & { 1 . 7 1 1 9 } & { 0 . 4 6 1 7 } \\ { 8 . 4 9 1 3 } & { 7 . 4 3 1 3 } & { 7 . 0 6 0 5 } & { 0 . 9 7 1 3 } \\ { 9 . 3 3 9 9 } & { 3 . 9 2 2 3 } & { 0 . 3 1 8 3 } & { 8 . 2 3 4 6 } \end{array} \right) , \mathbf { b } = \left( \begin{array} { c } { 1 3 0 . 3 2 4 2 } \\ { 4 2 . 9 3 4 8 } \\ { 1 4 9 . 9 8 9 3 } \\ { 8 3 . 1 9 5 3 } \end{array} \right) \]
program main
    implicit none
    integer,  parameter :: n = 4
    real*8 :: a(n,n), l(n,n), u(n,n), b(n), x(n), y(n)
    integer :: i

    a = reshape([ &
        6.5574d0, 6.7874d0, 6.5548d0, 2.7692d0, &
        0.3571d0, 7.5774d0, 1.7119d0, 0.4617d0, &
        8.4913d0, 7.4313d0, 7.0605d0, 0.9713d0, &
        9.3399d0, 3.9223d0, 0.3183d0, 8.2346d0  &
    ], shape(a), order=[2,1])

    b = [130.3242d0, 42.9348d0, 149.9893d0, 83.1953d0]

    call doolittle(a, l, u, n)

    ! 解 Ly = b
    call lowtri(l, b, y, n)

    ! 解 U x = y
    call uptri(u, y, x, n)

    print *, "Solution vector x:"
    write(*, 100) x

100 format(4F12.6)
end program main

输出:

 Solution vector x:
    6.948332    3.170983    9.502135    0.344460

注意:子程序中默认:implicit real*8(a-z)

参考文献

  1. 宋叶志,茅永兴,赵秀杰.Fortran 95/2003科学计算与工程[M].清华大学出版社,2011.