import numpy as np
import sys
def LU_deco_inverse(m):
dim = m.shape[0]
E = np.mat(np.eye(dim))
L = np.mat(np.eye(dim))
U = m.copy()
for i in range(dim):
if abs(m[i,i]) < 1e-8:
print("zero pivot encoUnted")
sys.exit()
# 上面L=m.copy()时用这个,然后我们将其改进先使其初始为单位阵
# L[:i,i] = 0
# L[i:dim,i] = U[i:dim,i] / U[i,i]
L[i+1:,i] = U[i+1:,i] / U[i,i]
# E[i+1:dim,i+1:dim] = E[i+1:dim,i+1:dim] - L[i+1:dim,i]*E[i,i+1:dim]
# 行变换应该是整个一行的变,而不是上面写的变部分,另E的变换一定要在U之前。
# 这里还将dim去掉因为意思就是从j+1到最后一个元素,可省略dim看起来没那么晕。
E[i+1:,:] = E[i+1:,:] - L[i+1:,i]*E[i,:]
U[i+1:,:] = U[i+1:,:] - L[i+1:,i]*U[i,:]
# U[i+1:dim,:i+1] = 0
# U[i+1:dim,i+1:dim] = U[i+1:dim,i+1:dim] - L[i+1:dim,i]*U[i,i+1:dim]
# 上面这个这样写不划算采用上上面那句代替这俩
print("\nLU分解后的L,U矩阵:")
print("L=",L)
print("U=",U)
print("将A化为上三角阵U后随之变换的E矩阵:")
print("E=",E)
# 普通从最后一行开始消去该列的for循环
# U = U.copy()
# for i in range(dim-1,-1,-1):
# E[i,:] = E[i,:]/U[i,i]
# U[i,:] = U[i,:]/U[i,i]
# for j in range(i-1,-1,-1):
# E[j,:] = E[j,:] - U[j,i]*E[i,:]
# U[j,:] = U[j,:] - U[j,i]*U[i,:]
# 写成向量形式
# U = U.copy()
# for i in range(dim-1,-1,-1):
# E[i,:] = E[i,:]/U[i,i]
# U[i,:] = U[i,:]/U[i,i]
# E[i-1:-1:-1,:] = E[i-1:-1:-1,:] - U[i-1:-1:-1,i]*E[i,:]
# U[i-1:-1:-1,:] = U[i-1:-1:-1,:] - U[i-1:-1:-1,i]*U[i,:]
# 通过观察做行变换的过程中发现的规律,比上面注释掉的方法更简单
E1 = np.mat(np.eye(dim)) # 这个E1用来求U的逆
for i in range(dim-1,-1,-1):
# 对角元单位化
E[i,:] = E[i,:]/U[i,i]
E1[i,:] = E1[i,:]/U[i,i]
U[i,:] = U[i,:]/U[i,i]
E[:i,:] = E[:i,:] - U[:i,i]*E[i,:]
E1[:i,:] = E1[:i,:] - U[:i,i]*E1[i,:]
U[:i,:] = U[:i,:] - U[:i,i]*U[i,:] # r_j = m_ji - r_j*r_i
print("\n将上三角阵U变为单位阵后的U和随之变换后的E分别为:")
print("U=",U)
print("E=",E)
print("使用系统自带的求inverse方法得到的逆为:")
print("m_inv=",m.I)
print("\nU的逆E1为:")
print("E1=",E1)
# 当然,我们还可以来求一下下三角阵L的逆
E2 = np.mat(np.eye(dim))
for i in range(dim):
# 因为这里对角元已经是1了就不做对角元单位化这部了
E2[i+1:,:] = E2[i+1:,:] - L[i+1:,i]*E2[i,:]
L[i+1:,:] = L[i+1:,:] - L[i+1:,i]*U[i,:]
print("\n将下三角阵L变为单位阵后的L和随之变换后的E2分别为:")
print("L=",L)
print("E2=",E2)
print("\n由A=LU,得A逆=U的逆*L的逆")
print("U的逆E1*L的逆E2=",E1*E2)
if __name__ == "__main__":
A = np.mat([[1.,1,1],[1,2,3],[1,5,1]])
A_dim = A.shape[0]
LU_deco_inverse(A)
LU分解后的L,U矩阵:
L= [[ 1. 0. 0.]
[ 1. 1. 0.]
[ 1. 4. 1.]]
U= [[ 1. 1. 1.]
[ 0. 1. 2.]
[ 0. 0. -8.]]
将A化为上三角阵U后随之变换的E矩阵:
E= [[ 1. 0. 0.]
[-1. 1. 0.]
[ 3. -4. 1.]]
将上三角阵U变为单位阵后的U和随之变换后的E分别为:
U= [[ 1. 0. 0.]
[ 0. 1. 0.]
[-0. -0. 1.]]
E= [[ 1.625 -0.5 -0.125]
[-0.25 0. 0.25 ]
[-0.375 0.5 -0.125]]
使用系统自带的求inverse方法得到的逆为:
m_inv= [[ 1.625 -0.5 -0.125]
[-0.25 0. 0.25 ]
[-0.375 0.5 -0.125]]
U的逆E1为:
E1= [[ 1. -1. -0.125]
[ 0. 1. 0.25 ]
[-0. -0. -0.125]]
将下三角阵L变为单位阵后的L和随之变换后的E2分别为:
L= [[ 1. 0. 0.]
[ 0. 1. 0.]
[ 0. 0. 1.]]
E2= [[ 1. 0. 0.]
[-1. 1. 0.]
[ 3. -4. 1.]]
由A=LU,得A逆=U的逆*L的逆
U的逆E1*L的逆E2= [[ 1.625 -0.5 -0.125]
[-0.25 0. 0.25 ]
[-0.375 0.5 -0.125]]
[Finished in 0.7s]
通过上诉结果可以看到:
通过 [ A | E ] ---> [ E | A' ] 初等行变换得到的结果 与“ 由A=LU,得A' = U' * L' ”(这里'为逆的意思) 还与 系统自带的求逆方法得到的结果是相等的。
通过该程序,我们可以提取出:1、方阵的LU分解;2、方阵求逆(有逆的情况下);3、上、下三角阵求逆。三个方法。
以上主要为一个LU分解的矩阵求逆方法
这里是使用 [ A | E ] ---> [ E | A' ] 做初等行变换的方法 这里A'为A的逆
1、在将A分解为LU时,U为做初等行变换后化来的矩阵,故[ A | E ] ---> [ U | E1 ]
2、然后再将上三角阵U求逆,继续做初等行变换,[ U | E ] ---> [ E | E2 ] 则这里的E2即为A的逆
综合上诉就是: [ A | E ] ---> [ U | E1 ] ---> [ E | E2 ]
下面为上下三角阵的求逆算法:
而LU分解的算法步骤呢,有点类似于L求逆的步骤(如下图)
下面总结一下这个项目:
1、该程序尽量避免了for循环使用numpy矩阵计算,节省了时间。
2、再对E做行变换时,记得把E放在U之前变
3、之前写了一个基于A=LU分解的得到A=PDQ,求出每个Pi和Qi,则A = Pn*...*P2*P1*D*Q1*Q2*...*Qn 得 P'n*...*P'2*P'1*A*Q'1*Q'2*...*Q'n*D' = E 然后再用P'n*...*P'2*P'1*E*Q'1*Q'2*...*Q'n*D' = A' 得到A的逆。但是这里原理上就错误了,因为把AE放在一起之后做初等变换只能单独做行变换或列变换,但这里既做了行变换又做了列变换,原理上就错了!