Python-用LU分解求解线性方程组的数值问题 信息
操作系统:Manjaro Linux 开发环境:Spyder4(Python 3.7) Libs:NumpyPython-用LU分解求解线性方程组的数值问题 信息,python,python-3.x,numpy,numerical-methods,Python,Python 3.x,Numpy,Numerical Methods,操作系统:Manjaro Linux 开发环境:Spyder4(Python 3.7) Libs:Numpy 问题 嗨 我用以下三种方法编写了一些求解线性方程组的函数: LU分解 雅可比法 高斯-赛德尔法 程序运行得很好。然而,LU分解的结果让我感到困扰。 例如,如果我的矩阵A和向量b是 A = np.array([[10., -1., 2., 0.], [-1., 11., -1., 3.], [2., -1., 10., -1.],
问题 嗨 我用以下三种方法编写了一些求解线性方程组的函数:
A = np.array([[10., -1., 2., 0.],
[-1., 11., -1., 3.],
[2., -1., 10., -1.],
[0., 3., -1., 8.]])
b = np.array([6., 25., -11., 15.])
那么我的结果是
编辑1: 我修复了这个问题,它只是LU分解期间代码中的一个bug。感谢大家的反馈
共享代码如下:
您的代码中有许多内容需要解决:
- Python不需要;为了结束一行,python知道行何时结束。Python只使用;将两行代码放在同一物理行上。比如“x=7;打印(x)”李>
- 如果在列表理解中不使用变量,则习惯上使用x。例如,[0表示范围(10)]。当然,python有更好的方法“[0]*10”李>
- 我注意到您导入了numpy,但没有对numpy数组使用操作。这将大大改进您的代码(并使其更快),使其更易于阅读。例如,您可以一次写入和读取整行或整列。“矩阵[0,:]”(第1行),“矩阵[:,0]”(第1列)李>
- 不需要在python中包含对象的长度,因为python会自动存储其对象的长度,这总是可以使用len()内置函数进行检索李>
- 对于您的代码来说并不重要(因为您可能是为了练习而这样做的),但您可能已经知道,lu分解已经存在,例如scipy.linalg.lu()。事实上,快速检查linalg.lu(a,True)可以发现,您的L和U中都有bug
- 看到您手动生成L和U矩阵,然后继续在L和U上使用np.linalg.inv(),这真的很奇怪。如果您愿意使用np.linalg.inv()函数,那么您的答案是一行,“np.linalg.inv(A)@b”。通常,人们会发现L和U更容易为X手动求解。找到L和U,然后使用numpy的反函数,有点达不到目的李>
- 尽管python有时会有所帮助,但它并不要求您在创建对象之前在内存中留出空间。Python自动管理内存的创建和删除(无需创建空的零列表)李>
- 点()只是python中手动访问“@”操作符的方法李>
import numpy as np
from scipy import linalg
def lu_dec_solver_v1(A,b):
return np.linalg.inv(A) @ b
def lu_dec_solver_v2(A,b):
L, U = linalg.lu(A,True)
L_inv = np.linalg.inv(L)
U_inv = np.linalg.inv(U)
return U_inv @ (L_inv @ b)
def lu_dec_solver_v3(A,b):
U = A.copy()
L = np.identity(len(A))
for n in range(0,len(A)-1):
for m in range(n+1,len(A)):
L[m,n] = U[m,n]/U[n,n]
U[m,:] += -L[m,n]*U[n,:]
L_inv = np.linalg.inv(L)
U_inv = np.linalg.inv(U)
return U_inv @ (L_inv @ b)
如果您想自己实现LU分解,那么这段代码不需要任何外部库。我把它附加在这里,以防你只是想复制它
def Abs(x):
'''
Input x and you'll get the abs.
'''
#Not the best way, but it is an easy way to not use numpy
return (x**2)**0.5
def ind_max(row,N):
'''
Find the index of the maximum of a list (row) of lentgth N.
'''
_in=0
_max=row[0]
i=0
while i<N:#the end of the row should be included (convension in how I use LUP..)
if row[i]>_max:
_max=row[i]
_in=i
i+=1
return _in
def Sum(List,N):
'''
Calculates the sum of a List of size N
'''
s=0
for i in range(N):
s+=List[i]
return s
def index_swap(A,index_1,index_2):
'''
index_swap takes an array and interchanges
A[index_1] with A[index_2].
Example:
A=[0,1,2,3]
index_swap(A,0,2)
A
>>[2, 1, 0, 3]
'''
tmp=A[index_1]
A[index_1]=A[index_2]
A[index_2]=tmp
def apply_permutations_vector(A,P,N):
'''
Applies the permutations given by P from LUP
to a list A of length N, and returns the result.
Example:
A=[1,2,5,8,3]
P=[2,4,0,3,1]
apply_permutations_vector(A,P,5)
>>[5, 3, 1, 8, 2]
'''
#that is, you make a list like this (P basically gives you the indices of A):)
Ap=[A[ P[i] ] for i in range(N)]
return Ap
def apply_permutations_matrix(M,P,N):
'''
Applies the permutations given by P from LUP
to a N*N array M of length N, and returns the result.
M=[
[ 0, 2, 2 , 3 , 5],
[-3, -1, 1 , 5 , 9],
[ 1, -1, 1 , 4 , 7],
[ 1, -1, 1 , 0 , 2],
[ 1, -1, 1 , 0 , 3]
]
P=[2,0,1,4,3]
apply_permutations_matrix(M,P,5)
>>[
[ 1, -1, 1, 4, 7],
[ 0, 2, 2, 3, 5],
[-3, -1, 1, 5, 9],
[ 1, -1, 1, 0, 3],
[ 1, -1, 1, 0, 2]
]
'''
Mp=[ [M[ P[i] ][j]for j in range(N)] for i in range(N) ]
return Mp
def LUP(M,N,_tiny=1e-20):
U=[ [ M[i][j] for j in range(N)] for i in range(N) ]
L=[ [ 0 if i!=j else 1 for j in range(N)] for i in range(N) ]
#this is the "permutation vector". if it is e.g. [2 1 0 3] it means you make 0<->2
P=[ i for i in range(N) ]
for k in range(1,N):
for i in range(k,N):
#find the index of the maximum in column
_col=[Abs(U[_r][k-1]) for _r in range(k-1,N)]
#find the index of the maximum of _col
# notice that the length of _col is N-(k-1)
len_col=N-(k-1)
pivot=ind_max( _col ,len_col) + k - 1 #convert the index of _col (it has a length of len_col) to the index of a row of U
##################################################
#if you remove it, then you get a lot of infinities
#it has to do with the fact that if U[pivot][k-1] <_tiny , then U[k-1][k-1] will be a zero,
#L[i][k-1] explodes.
#You are allowed to skip this i, then, because if U[pivot][k-1] <_tiny , then all U[i][k-1] are small!
#Check that this is true by uncommenting print(_col)
if Abs(U[pivot][k-1]) < _tiny :
#print(_col)
break
###################################################
#if the maximum is not at k-1, swap!
if pivot != k-1 :
# Permute rows k-1 and pivot in U
index_swap(P,k-1,pivot)
tmpU=[U[k-1][_r] for _r in range(k-1,N)]
#print(U)
for _r in range(k-1,N):
U[k-1][_r]=U[pivot][_r]
#print(U)
for _r in range(k-1,N):
U[pivot][_r]=tmpU[_r-(k-1)]#again we have to convert the index of tmpU
#print(U)
#print("=========================")
tmpL=[L[k-1][_r] for _r in range(k-1)]
#print(L)
for _r in range(k-1):
L[k-1][_r]=L[pivot][_r]
#print(L)
for _r in range(k-1):
L[pivot][_r]=tmpL[_r]
#print(L)
#print("========================")
L[i][k-1]=U[i][k-1]/U[k-1][k-1]
for j in range(k-1,N):
U[i][j]=U[i][j]-L[i][k-1]*U[k-1][j]
return L,U,P
def Abs(x):
'''
输入x,你就会得到abs。
'''
#这不是最好的方法,但这是一种不使用numpy的简单方法
返回(x**2)**0.5
def ind_max(第N行):
'''
查找lentgth N的列表(行)的最大值的索引。
'''
_in=0
_最大值=行[0]
i=0
而我(马克斯):
_最大值=行[i]
_in=i
i+=1
返回
定义和(列表,N):
'''
计算大小为N的列表的总和
'''
s=0
对于范围(N)中的i:
s+=列表[i]
返回s
def索引交换(A、索引1、索引2):
'''
索引交换采用数组并交换
带[index_2]的[index_1]。
例子:
A=[0,1,2,3]
指数交换(A,0,2)
A.
>>[2, 1, 0, 3]
'''
tmp=A[指数1]
A[index_1]=A[index_2]
A[index_2]=tmp
定义应用置换向量(A,P,N):
'''
应用LUP中P给出的置换
返回长度为N的列表,并返回结果。
例子:
A=[1,2,5,8,3]
P=[2,4,0,3,1]
应用置换向量(A,P,5)
>>[5, 3, 1, 8, 2]
'''
#也就是说,你做了一个这样的列表(P基本上给出了a的索引):)
Ap=[A[P[i]]表示范围(N)内的i]
返回Ap
def应用置换矩阵(M,P,N):
'''
应用LUP中P给出的置换
到长度为N的N*N数组M,并返回结果。
M=[
[ 0, 2, 2 , 3 , 5],
[-3, -1, 1 , 5 , 9],
[ 1, -1, 1 , 4 , 7],
[ 1, -1, 1 , 0 , 2],
[ 1, -1, 1 , 0 , 3]
]
P=[2,0,1,4,3]
应用置换矩阵(M,P,5)
>>[
[ 1, -1, 1, 4, 7],
[ 0, 2, 2, 3, 5],
[-3, -1, 1, 5, 9],
[ 1, -1, 1, 0, 3],
[ 1, -1, 1, 0, 2]
]
'''
Mp=[[M[P[i][j]表示范围(N)中的j]表示范围(N)中的i]
返回Mp
def LUP(M,N,_-tiny=1e-20):
U=[[M[i][j]表示范围(N)中的j]表示范围(N)中的i]
L=[[0如果i!=j,则范围(N)中的j为1]范围(N)中的i为1]
#这是“排列向量”。如果它是例如[2 1 0 3],则意味着您获得了02
P=[i代表范围(N)内的i]
对于范围(1,N)内的k:
对于范围(k,N)内的i:
#查找列中最大值的索引
_col=[Abs(U[_-r][k-1]),表示范围(k-1,N)]
#查找_col的最大值的索引
#请注意_col的长度是N-(k-1)
len_col=N-(k-1)
pivot=ind_max(_col,len_col)+k-1#将_col的索引(长度为len_col)转换为一行U的索引
##################################################
#如果你去掉它,你会得到很多无穷大
#这与事实有关,如果U[pivot][k-1],我认为对于这种尺寸,舍入误差太大了
def Abs(x):
'''
Input x and you'll get the abs.
'''
#Not the best way, but it is an easy way to not use numpy
return (x**2)**0.5
def ind_max(row,N):
'''
Find the index of the maximum of a list (row) of lentgth N.
'''
_in=0
_max=row[0]
i=0
while i<N:#the end of the row should be included (convension in how I use LUP..)
if row[i]>_max:
_max=row[i]
_in=i
i+=1
return _in
def Sum(List,N):
'''
Calculates the sum of a List of size N
'''
s=0
for i in range(N):
s+=List[i]
return s
def index_swap(A,index_1,index_2):
'''
index_swap takes an array and interchanges
A[index_1] with A[index_2].
Example:
A=[0,1,2,3]
index_swap(A,0,2)
A
>>[2, 1, 0, 3]
'''
tmp=A[index_1]
A[index_1]=A[index_2]
A[index_2]=tmp
def apply_permutations_vector(A,P,N):
'''
Applies the permutations given by P from LUP
to a list A of length N, and returns the result.
Example:
A=[1,2,5,8,3]
P=[2,4,0,3,1]
apply_permutations_vector(A,P,5)
>>[5, 3, 1, 8, 2]
'''
#that is, you make a list like this (P basically gives you the indices of A):)
Ap=[A[ P[i] ] for i in range(N)]
return Ap
def apply_permutations_matrix(M,P,N):
'''
Applies the permutations given by P from LUP
to a N*N array M of length N, and returns the result.
M=[
[ 0, 2, 2 , 3 , 5],
[-3, -1, 1 , 5 , 9],
[ 1, -1, 1 , 4 , 7],
[ 1, -1, 1 , 0 , 2],
[ 1, -1, 1 , 0 , 3]
]
P=[2,0,1,4,3]
apply_permutations_matrix(M,P,5)
>>[
[ 1, -1, 1, 4, 7],
[ 0, 2, 2, 3, 5],
[-3, -1, 1, 5, 9],
[ 1, -1, 1, 0, 3],
[ 1, -1, 1, 0, 2]
]
'''
Mp=[ [M[ P[i] ][j]for j in range(N)] for i in range(N) ]
return Mp
def LUP(M,N,_tiny=1e-20):
U=[ [ M[i][j] for j in range(N)] for i in range(N) ]
L=[ [ 0 if i!=j else 1 for j in range(N)] for i in range(N) ]
#this is the "permutation vector". if it is e.g. [2 1 0 3] it means you make 0<->2
P=[ i for i in range(N) ]
for k in range(1,N):
for i in range(k,N):
#find the index of the maximum in column
_col=[Abs(U[_r][k-1]) for _r in range(k-1,N)]
#find the index of the maximum of _col
# notice that the length of _col is N-(k-1)
len_col=N-(k-1)
pivot=ind_max( _col ,len_col) + k - 1 #convert the index of _col (it has a length of len_col) to the index of a row of U
##################################################
#if you remove it, then you get a lot of infinities
#it has to do with the fact that if U[pivot][k-1] <_tiny , then U[k-1][k-1] will be a zero,
#L[i][k-1] explodes.
#You are allowed to skip this i, then, because if U[pivot][k-1] <_tiny , then all U[i][k-1] are small!
#Check that this is true by uncommenting print(_col)
if Abs(U[pivot][k-1]) < _tiny :
#print(_col)
break
###################################################
#if the maximum is not at k-1, swap!
if pivot != k-1 :
# Permute rows k-1 and pivot in U
index_swap(P,k-1,pivot)
tmpU=[U[k-1][_r] for _r in range(k-1,N)]
#print(U)
for _r in range(k-1,N):
U[k-1][_r]=U[pivot][_r]
#print(U)
for _r in range(k-1,N):
U[pivot][_r]=tmpU[_r-(k-1)]#again we have to convert the index of tmpU
#print(U)
#print("=========================")
tmpL=[L[k-1][_r] for _r in range(k-1)]
#print(L)
for _r in range(k-1):
L[k-1][_r]=L[pivot][_r]
#print(L)
for _r in range(k-1):
L[pivot][_r]=tmpL[_r]
#print(L)
#print("========================")
L[i][k-1]=U[i][k-1]/U[k-1][k-1]
for j in range(k-1,N):
U[i][j]=U[i][j]-L[i][k-1]*U[k-1][j]
return L,U,P