矩阵的LU分解法——Python实现

理论参考:

LU分解、LDLT分解和Cholesky分解          https://blog.csdn.net/zhouliyang1990/article/details/21952485

Doolittle分解法(LU分解)详细分析以及matlab的实现    https://blog.csdn.net/lol_IP/article/details/78491457

 

       在线性代数中,LU分解(LU Decomposition)是矩阵分解的一种,可以将一个矩阵分解为一个单位下三角矩阵和一个上三角矩阵的乘积(有时是它们和一个置换矩阵的乘积)。LU分解主要应用在数值分析中,用来解线性方程、求反矩阵或计算行列式。

        LU分解在本质上是高斯消元法的一种表达形式。实质上是将A通过初等行变换变成一个上三角矩阵,其变换矩阵就是一个单位下三角矩阵。这正是所谓的杜尔里特算法(Doolittle algorithm):从下至上地对矩阵A做初等行变换,将对角线左下方的元素变成零,然后再证明这些行变换的效果等同于左乘一系列单位下三角矩阵,这一系列单位下三角矩阵的乘积的逆就是L矩阵,它也是一个单位下三角矩阵。这类算法的复杂度一般在(三分之二的n三次方) 左右。

伪代码:

算法 LU Decomposition 
//输入矩阵A[1…n,1…n],并且A的所有顺序主子式都不为0
//输出下三角矩阵L和上三角矩阵U
L←n阶zero矩阵  //初始化一个n阶zero矩阵
U←n阶zero矩阵 
for i ← 1 to n do
	L[i][i] ← 1 //L的主对角线元素全为1
        if i==0 do  //分别利用A的第一行元素第一列元素,确定L的第一列元素和U的第一行元素
        U[0][0] ← A[0][0] 			      
		for j ← 1 to n do
			U[0][j] ←A[0][j]
			L[j][0] ←A[j][0]/U[0][0]
	else
		for j ← i to n do  //计算矩阵U
			for k ← 1 to i-1 do
				temp ←L[i][k] * U[k][j]
			U[i][j] ←A[i][j]-temp
		for j ← i+1 to n do  //计算矩阵L
			for k ← 1 to i-1 do
				temp ←L[j][k] * U[k][i]
			L[j][i] ← (A[j][i] - temp)/U[i][i]

代码实现:

import numpy as np
import pandas as pd

np.random.seed(2)
def LU_decomposition(A):
    n=len(A[0])
    L = np.zeros([n,n])
    U = np.zeros([n, n])
    for i in range(n):
        L[i][i]=1
        if i==0:
            U[0][0] = A[0][0]
            for j in range(1,n):
                U[0][j]=A[0][j]
                L[j][0]=A[j][0]/U[0][0]
        else:
                for j in range(i, n):#U
                    temp=0
                    for k in range(0, i):
                        temp = temp+L[i][k] * U[k][j]
                    U[i][j]=A[i][j]-temp
                for j in range(i+1, n):#L
                    temp = 0
                    for k in range(0, i ):
                        temp = temp + L[j][k] * U[k][i]
                    L[j][i] = (A[j][i] - temp)/U[i][i]
    return L,U

if __name__ == '__main__': 
    #A=np.random.randint(1,10,size=[3,3])  #注意A的顺序主子式大于零
    A=[[2,-1,1],[4,1,-1],[1,1,1]]      #举一个例子
    L,U=LU_decomposition(A)
    print(L,'\n',U)

 实验结果:

改进1:

        在相同的输入情况下,LU分解法比Gauss消去法、列主元素消去法两者效率更高。因为一旦得到了LU矩阵无论右边是什么样的B向量,都可以用AX=B来求解。同时LU分解不是非得需要额外的存储空间,我们把U的非零部分存储到A的上三角部分,把L的非零部分存储到A的下三角部分,可以如下:

import numpy as np
import pandas as pd

def LU_decomposition(A):
    n=len(A[0])
    for i in range(n):
        if i==0:
            for j in range(1,n):
               A[j][0]=A[j][0]/A[0][0]
        else:
                for j in range(i, n):#U
                    temp=0
                    for k in range(0, i):
                        temp = temp+A[i][k] * A[k][j]
                    A[i][j]=A[i][j]-temp
                for j in range(i+1, n):#L
                    temp = 0
                    for k in range(0, i ):
                        temp = temp + A[j][k] * A[k][i]
                    A[j][i] = (A[j][i] - temp)/A[i][i]
    return A

if __name__ == '__main__':
    #A=np.random.randint(1,10,size=[3,3])
    A=[[2,-1,1],[4,1,-1],[1,1,1]]
    A=LU_decomposition(A)
    print(A)

       但是,上面并没有给出LU分解的前提,也就是当n阶矩阵A的顺序主子式都非零的时候存在唯一的Doolittle分解,如果出现顺序主子式为零的时候则会出错,如下:

       因此在此之前应该对A的顺序主子式进行判别。最终版完整代码如下:

import numpy as np
import pandas as pd

#np.random.seed(2)
def det(A):     #求A的行列式
    if len(A) <= 0:
        return None
    elif len(A) == 1:
        return A[0][0]
    else:
        s = 0
        for i in range(len(A)):
            n = [[row[a] for a in range(len(A)) if a != i] for row in A[1:]]  # 这里生成余子式
            s += A[0][i] * det(n) * (-1) ** (i )
        return s

def Master_Sequential(A,n):   #判断A的k阶顺序主子式是否非零,非零满足LU分解的条件
    for i in range(0,n):
        Master = np.zeros([i+1,i+1])
        for row in range(0,i+1):
            for a in range(0,i+1):
                Master[row][a]=A[row][a]
        if det(Master)==0:
            done=False
            return done


def LU_decomposition(A):
    n=len(A[0])
    L = np.zeros([n,n])
    U = np.zeros([n, n])
    for i in range(n):
        L[i][i]=1
        if i==0:
            U[0][0] = A[0][0]
            for j in range(1,n):
                U[0][j]=A[0][j]
                L[j][0]=A[j][0]/U[0][0]
        else:
                for j in range(i, n):#U
                    temp=0
                    for k in range(0, i):
                        temp = temp+L[i][k] * U[k][j]
                    U[i][j]=A[i][j]-temp
                for j in range(i+1, n):#L
                    temp = 0
                    for k in range(0, i ):
                        temp = temp + L[j][k] * U[k][i]
                    L[j][i] = (A[j][i] - temp)/U[i][i]
    return L,U

if __name__ == '__main__':
    n=3
    #A=[[2,-1,1],[4,1,-1],[1,1,1]]
    #A = np.random.randint(1, 10, size=[n, n])
    A=[[5,9,3],[5,9,1],[5,1,9]]

    print('A矩阵:\n',A)
    if Master_Sequential(A,n) != False:
        L,U=LU_decomposition(A)
        print('L矩阵:\n',L, '\nU矩阵:\n',U)
    else:
        print('A的k阶主子式不全非零,不满足LU分解条件。')

 

 本文来自CSDN博客,转载请标明出处:https://blog.csdn.net/dgq18764215279/article/details/89201238

 

  • 43
    点赞
  • 148
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值