您可以用于scipy.sparse.linalg.splu
获取分解的下 ( L
) 和上 ( U
) 三角矩阵的稀疏矩阵:M=LU
from scipy.sparse.linalg import splu
lu = splu(M)
行列式det(M)
可以表示为:
det(M) = det(LU) = det(L)det(U)
三角矩阵的行列式只是对角项的乘积:
diagL = lu.L.diagonal()
diagU = lu.U.diagonal()
d = diagL.prod()*diagU.prod()
但是,对于大型矩阵,通常会发生下溢或上溢,这可以通过使用对数来避免。
diagL = diagL.astype(np.complex128)
diagU = diagU.astype(np.complex128)
logdet = np.log(diagL).sum() + np.log(diagU).sum()
请注意,我调用复数算术来解释可能出现在对角线上的负数。现在,logdet
您可以从中恢复行列式:
det = np.exp(logdet) # usually underflows/overflows for large matrices
而行列式的符号可以直接从diagL
和计算diagU
(例如在实施 Crisfield 的弧长方法时很重要):
sign = swap_sign*np.sign(diagL).prod()*np.sign(diagU).prod()
其中swap_sign
是考虑 LU 分解中排列数的术语。感谢@Luiz Felippe Rodrigues,可以计算出:
swap_sign = minimumSwaps(lu.perm_r)
def minimumSwaps(arr):
"""
Minimum number of swaps needed to order a
permutation array
"""
# from https://www.thepoorcoder.com/hackerrank-minimum-swaps-2-solution/
a = dict(enumerate(arr))
b = {v:k for k,v in a.items()}
count = 0
for i in a:
x = a[i]
if x!=i:
y = b[i]
a[y] = x
b[x] = y
count+=1
return count