基于Python实现的矩阵Doolittle分解及应用

若方阵A的各阶主子式不为0,则矩阵 A A A可分解为 A = L U A=LU A=LU L L L为下三角矩阵, U U U为上三角矩阵,这种方法称为矩阵的Doolittle分解。

主元直接分解

原理

A = L U A = LU A=LU,则有
[ a 11 a 12 ⋯ a 1 n a 21 a 22 … a 2 n ⋮ ⋮ ⋮ a n 1 a n 2 … a n n ] = [ 1 0 ⋯ 0 l 21 1 … 0 ⋮ ⋮ ⋱ ⋮ l n 1 l n 2 … 1 ] [ u 11 u 12 ⋯ u 1 n 0 u 22 … u 2 n ⋮ ⋮ ⋱ ⋮ 0 0 … u n n ] \begin{bmatrix}a_{11}&a_{12}&\cdots&a_{1n}\\a_{21}&a_{22}&\dots&a_{2n}\\\vdots&\vdots&&\vdots\\a_{n1}&a_{n2}&\dots&a_{nn}\end{bmatrix}=\begin{bmatrix}1&0&\cdots&0\\l_{21}&1&\dots&0\\\vdots&\vdots&\ddots&\vdots\\l_{n1}&l_{n2}&\dots&1\end{bmatrix}\begin{bmatrix}u_{11}&u_{12}&\cdots&u_{1n}\\0&u_{22}&\dots&u_{2n}\\\vdots&\vdots&\ddots&\vdots\\0&0&\dots&u_{nn}\end{bmatrix} a11a21an1a12a22an2a1na2nann=1l21ln101ln2001u1100u12u220u1nu2nunn
根据矩阵乘法可得
a i j = ∑ m = 1 n l i m u m j ,              i , j = 1 , 2 , … , n a_{ij}=\sum_{m=1}^nl_{im}u_{mj},\;\;\;\;\;\;i,j=1,2,\dots,n aij=m=1nlimumj,i,j=1,2,,n
可以发现 l i i = 1 , l_{ii}=1, lii=1且L为下三角矩阵,U为上三角矩阵,利用这些信息可以得到
a i j = ∑ m = 1 i − 1 l i m u m j + u i j    a i j = ∑ m = 1 j − 1 l i m u m j + l i j u j j a_{ij}=\sum_{m=1}^{i-1}l_{im}u_{mj} + u_{ij}\\ \;\\ a_{ij}=\sum_{m=1}^{j-1}l_{im}u_{mj} + l_{ij}u_{jj} aij=m=1i1limumj+uijaij=m=1j1limumj+lijujj

就可以计算L和U了,具体公式如下

计算 u i j u_{ij} uij
u i j = a i j − ∑ m = 1 i − 1 l i m u m j u_{ij}=a_{ij}-\sum_{m=1}^{i-1}l_{im}u_{mj} uij=aijm=1i1limumj
计算 l i j l_{ij} lij
l i j = a i j − ∑ m = 1 j − 1 l i m u m j u j j l_{ij}=\frac{a_{ij}-\sum_{m=1}^{j-1}l_{im}u_{mj} }{u_{jj}} lij=ujjaijm=1j1limumj

代码

def Dolittle(Matrix):
#事实上,w、L、U可以用一个矩阵存储,为了方便理解,写成了三个矩阵
    w = Matrix.shape[0]
    L = np.zeros((w,w))
    U = np.zeros((w,w))

    #U的第一行
    U[0,:] = Matrix[0,:]
    #L的主元和第一列
    for i in range(w):
        L[i,i] = 1
        L[i,0] = Matrix[i,0] / U[0,0]
    for i in range(1,w):
        for j in range(i,w):
            #U的第i行
            U[i,j] = Matrix[i,j] - np.dot(L[i,:i],U[:i,j])
            #L的第i列
            if(j+1<w):
                L[j+1,i] = (Matrix[j+1,i] - np.dot(L[j+1,:i],U[:i,i]))/U[i,i]
    return L,U

实验

Matrix = np.array([
    [2,1,1],[4,4,3],[6,7,7]
])
L,U=Dolittle(Matrix)

结果

原矩阵:
原矩阵
L(分解得到的下三角矩阵):
在这里插入图片描述
U(分解得到的上三角矩阵):
在这里插入图片描述

主元直接分解解方程

直接上公式
A X = L U X = b AX = LUX = b AX=LUX=b
{ L y = b U x = y \left\{\begin{array}{l}Ly=b\\Ux=y\end{array}\right. {Ly=bUx=y
解方程组就完事了

代码

def SolveEquations(L,U,b):
    w = L.shape[0]
    x = np.zeros(w)
    y = np.zeros(w)
    for i in range(w):
        y[i] = (b[i] - np.dot(L[i,:],y.T))
    for i in range(w-1,-1,-1):
        x[i] = (y[i] - np.dot(U[i,:],x.T))/U[i,i]
    return x

列主元直接三角分解

上述三角消元法源于顺序Gauss消元法,没有选择主元,可能产声数值不稳定的现象,而列主元直接三角分解解决了这个问题。列主元三角分解的思想与列主元Guass消元法类似,需要选主元。

事实上,计算机在进行数值计算的过程中由于数字位数限制,计算的结果都是近似值,存在一定的误差。而在进行直接三角分解的过程中, U U U 的主元 U k k U_{kk} Ukk 会在计算 l i k l_{ik} lik 时作为分母,如果 U k k U_{kk} Ukk 太小,会使 l i k l_{ik} lik 很大,从而导致整个计算过程中的累计误差很大。

所以,计算矩阵 U U U 的第 k k k 行时,我们考察 U k k , U k + 1 k , … , U n k U_{kk},U_{k+1k},\dots,U_{nk} Ukk,Uk+1k,,Unk等元素,将该值最大的一行与第 k k k 行交换,然后计算其他元素的值。

在计算过程中矩阵会发生变换,此时不满足 A = L U A = LU A=LU,如果仍要写成等式的样子需要引入行变换矩阵 P P P 。即
P A = L U PA = LU PA=LU
代码

def Dolittle_Col(Matrix):
#事实上,w、L、U可以用一个矩阵存储,为了方便理解,写成了三个矩阵
    w = Matrix.shape[0]
    L = np.zeros((w,w))
    U = np.zeros((w,w))

    #U的第一行
    U[0,:] = Matrix[0,:]
    #L的主元和第一列
    for i in range(w):
        L[i,i] = 1
        L[i,0] = Matrix[i,0] / U[0,0]
    for i in range(1,w):
        #交换主元最大的行到第i行
        maxrow = i
        maxValue = float('-inf')
        for k in range(i,w):
            value = Matrix[k,i] - np.dot(L[k,:i],U[:i,i])
            if(maxValue<value):
                maxrow = k
                maxValue = value
        Matrix[[i,maxrow],:] = Matrix[[maxrow,i],:] #交换
        L[[i,maxrow],:i] = L[[maxrow,i],:i] #交换
        for j in range(i,w):
            #U的第i行
            U[i,j] = Matrix[i,j] - np.dot(L[i,:i],U[:i,j])
            #L的第i列
            if(j+1<w):
                L[j+1,i] = (Matrix[j+1,i] - np.dot(L[j+1,:i],U[:i,i]))/U[i,i]
    return L,U

实验

Matrix = np.array([
    [2,1,1],[4,4,3],[6,7,7]
])
L,U=Dolittle_Col(Matrix)

结果
原矩阵:
原矩阵
L(分解得到的下三角矩阵):
在这里插入图片描述
U(分解得到的上三角矩阵):
在这里插入图片描述

上面结果并不满足 A = L U A = LU A=LU,但是满足 P A = L U PA=LU PA=LU, L与U相乘的结果是A第二行与第三行互换后的样子。

主元直接分解求逆矩阵


X = A − 1 X = A^{-1}\\ X=A1
则有
A X = E AX = E\\ AX=E

X = ( x 1 , x 2 , … , x n )    E = ( e 1 , e 2 , … , e n ) X=(x_1,x_2,\dots,x_n)\\ \;\\ E=(e_1,e_2,\dots,e_n) X=(x1,x2,,xn)E=(e1,e2,,en)

A x i = e i Ax_i=e_i Axi=ei
对系数矩阵A使用直接三角分解,然后利用三角分解易解同系数矩阵的性质,解得每一个 x i x_i xi ,组成逆矩阵。

代码

def GetInverseMatrix(matrix):
    w = matrix.shape[0]
    L,U = Dolittle(matrix)
    inverseMatrix = np.zeros((w,w))
    for i in range(w):
        e = np.zeros(w)
        e[i]=1
        inverseMatrix[:,i] = SolveEquations(L,U,e)
    return inverseMatrix

实验
随便在百度找了一道求逆矩阵的题
在这里插入图片描述

A = np.array([[2,3,1],[0,1,3],[1,2,5]])
inverseMatrix = GetInverseMatrix(A)
print(inverseMatrix)

结果
在这里插入图片描述
答案
在这里插入图片描述

很好用有木有。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值