在 LU 分解中除以零警告 - 杜立特尔算法工作
Divide by Zero Warning in LU Decomposition- Doolittle Algorithm working
我已经按照以下 link 实现了矩阵 LU 分解的标准 equations/algorithm:(1) and (2)
returns 如下方矩阵的 LU 分解非常完美。
然而,我的问题是 - 它也给出了 Divide by Zero warning
.
代码在这里:
import numpy as np
def LUDecomposition (A):
L = np.zeros(np.shape(A),np.float64)
U = np.zeros(np.shape(A),np.float64)
acc = 0
L[0,0]=1
for i in np.arange(len(A)):
for k in range(i,len(A)):
for j in range(0,i):
acc += L[i,j]*U[j,k]
U[i,k] = A[i,k]-acc
for m in range(k+1,len(A)):
if m==k:
L[m,k]=1
else:
L[m,k] = (A[m,k]-acc)/U[k,k]
acc=0
return (L,U)
A = np.array([[-4, -1, -2],
[-4, 12, 3],
[-4, -2, 18]])
L, U = LUDecomposition (A)
我哪里错了?
您似乎在第一个内部级别 for
循环中犯了一些缩进错误:U
必须在 L
之前求值;您也没有正确计算求和项 acc
并且没有正确地将 L
的对角线项设置为 1。在进行一些其他语法修改之后,您可以按如下方式重写函数:
def LUDecomposition(A):
n = A.shape[0]
L = np.zeros((n,n), np.float64)
U = np.zeros((n,n), np.float64)
for i in range(n):
# U
for k in range(i,n):
s1 = 0 # summation of L(i, j)*U(j, k)
for j in range(i):
s1 += L[i,j]*U[j,k]
U[i,k] = A[i,k] - s1
# L
for k in range(i,n):
if i==k:
# diagonal terms of L
L[i,i] = 1
else:
s2 = 0 # summation of L(k, j)*U(j, i)
for j in range(i):
s2 += L[k,j]*U[j,i]
L[k,i] = (A[k,i] - s2)/U[i,i]
return L, U
这一次给出矩阵 A
的正确输出,与作为可靠参考的 scipy.linalg.lu 相比:
import numpy as np
from scipy.linalg import lu
A = np.array([[-4, -1, -2],
[-4, 12, 3],
[-4, -2, 18]])
L, U = LUDecomposition(A)
P, L_sp, U_sp = lu(A, permute_l=False)
P
>>> [[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
L
>>> [[ 1. 0. 0. ]
[ 1. 1. 0. ]
[ 1. -0.07692308 1. ]]
np.allclose(L_sp, L))
>>> True
U
>>> [[-4. -1. -2. ]
[ 0. 13. 5. ]
[ 0. 0. 20.38461538]]
np.allclose(U_sp, U))
>>> True
注意:与scipy lapack getrf 算法不同,此 Doolittle 实现不包括旋转,这两个比较仅在置换矩阵 P
时为真scipy.linalg.lu
返回的是单位矩阵, 即 scipy 没有执行任何排列,这确实是矩阵 A
的情况。 scipy算法确定的置换矩阵是为了优化结果矩阵的条件数,以减少舍入误差。最后,您可以简单地验证 A = LU
如果分解正确,情况总是如此:
A = np.random.rand(10,10)
L, U = LUDecomposition(A)
np.allclose(A, np.dot(L, U))
>>> True
不过,就数值效率和准确性而言,我不建议您使用自己的函数来计算 LU 分解。希望这会有所帮助。
我已经按照以下 link 实现了矩阵 LU 分解的标准 equations/algorithm:(1) and (2)
returns 如下方矩阵的 LU 分解非常完美。
然而,我的问题是 - 它也给出了 Divide by Zero warning
.
代码在这里:
import numpy as np
def LUDecomposition (A):
L = np.zeros(np.shape(A),np.float64)
U = np.zeros(np.shape(A),np.float64)
acc = 0
L[0,0]=1
for i in np.arange(len(A)):
for k in range(i,len(A)):
for j in range(0,i):
acc += L[i,j]*U[j,k]
U[i,k] = A[i,k]-acc
for m in range(k+1,len(A)):
if m==k:
L[m,k]=1
else:
L[m,k] = (A[m,k]-acc)/U[k,k]
acc=0
return (L,U)
A = np.array([[-4, -1, -2],
[-4, 12, 3],
[-4, -2, 18]])
L, U = LUDecomposition (A)
我哪里错了?
您似乎在第一个内部级别 for
循环中犯了一些缩进错误:U
必须在 L
之前求值;您也没有正确计算求和项 acc
并且没有正确地将 L
的对角线项设置为 1。在进行一些其他语法修改之后,您可以按如下方式重写函数:
def LUDecomposition(A):
n = A.shape[0]
L = np.zeros((n,n), np.float64)
U = np.zeros((n,n), np.float64)
for i in range(n):
# U
for k in range(i,n):
s1 = 0 # summation of L(i, j)*U(j, k)
for j in range(i):
s1 += L[i,j]*U[j,k]
U[i,k] = A[i,k] - s1
# L
for k in range(i,n):
if i==k:
# diagonal terms of L
L[i,i] = 1
else:
s2 = 0 # summation of L(k, j)*U(j, i)
for j in range(i):
s2 += L[k,j]*U[j,i]
L[k,i] = (A[k,i] - s2)/U[i,i]
return L, U
这一次给出矩阵 A
的正确输出,与作为可靠参考的 scipy.linalg.lu 相比:
import numpy as np
from scipy.linalg import lu
A = np.array([[-4, -1, -2],
[-4, 12, 3],
[-4, -2, 18]])
L, U = LUDecomposition(A)
P, L_sp, U_sp = lu(A, permute_l=False)
P
>>> [[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
L
>>> [[ 1. 0. 0. ]
[ 1. 1. 0. ]
[ 1. -0.07692308 1. ]]
np.allclose(L_sp, L))
>>> True
U
>>> [[-4. -1. -2. ]
[ 0. 13. 5. ]
[ 0. 0. 20.38461538]]
np.allclose(U_sp, U))
>>> True
注意:与scipy lapack getrf 算法不同,此 Doolittle 实现不包括旋转,这两个比较仅在置换矩阵 P
时为真scipy.linalg.lu
返回的是单位矩阵, 即 scipy 没有执行任何排列,这确实是矩阵 A
的情况。 scipy算法确定的置换矩阵是为了优化结果矩阵的条件数,以减少舍入误差。最后,您可以简单地验证 A = LU
如果分解正确,情况总是如此:
A = np.random.rand(10,10)
L, U = LUDecomposition(A)
np.allclose(A, np.dot(L, U))
>>> True
不过,就数值效率和准确性而言,我不建议您使用自己的函数来计算 LU 分解。希望这会有所帮助。