Похоже, что вы допустили некоторые ошибки в отступах относительно первого внутреннего уровня for
loop: 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
. Матрица перестановок, определенная в алгоритме Сципи, предназначена для оптимизации номеров условий результирующей матрицы с целью уменьшения ошибок округления. Наконец, вы можете просто проверить, что A = LU
, что всегда будет, если факторизация сделана правильно:
A = np.random.rand(10,10)
L, U = LUDecomposition(A)
np.allclose(A, np.dot(L, U))
>>> True
Тем не менее, с точки зрения численной эффективности и точности, я бы не рекомендовал вам использовать свою собственную функцию для вычисления разложения LU. Надеюсь, это поможет.