基于LU分解的矩阵求逆



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)
 



以上代码在配置好的sublime环境下运行结果为:
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分解的矩阵求逆_第1张图片基于LU分解的矩阵求逆_第2张图片

而LU分解的算法步骤呢,有点类似于L求逆的步骤(如下图)

基于LU分解的矩阵求逆_第3张图片

下面总结一下这个项目:

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放在一起之后做初等变换只能单独做行变换或列变换,但这里既做了行变换又做了列变换,原理上就错了!



你可能感兴趣的:(python)