如何在Python中进行Cholesky分解

时间:2013-01-18 22:46:18

标签: python numpy scipy

我正在尝试使用Cholesky分解,但是这个功能实际上并没有在scipy中实现,或者有些东西我不理解。我发布在这里是为了后者。这是我正在做的一个简化示例:

import numpy
import scipy.linalg

numpy.random.seed(0)
X = numpy.random.normal(size=(10,4))
V = numpy.dot(X.transpose(),X)
R = V.copy()
scipy.linalg.cholesky(R,False,overwrite_a=True)
print V
print R

我认为应该发生的是R被上三角矩阵覆盖。但是,当我运行此代码时,我的V和R出来的相同(cholesky不会覆盖R)。我误解了overwrite_a的目的,还是犯了其他错误?如果这只是scipy中的一个错误,是否有一种解决方法或其他方式我可以在Python中进行Cholesky分解?

3 个答案:

答案 0 :(得分:4)

使用

再试一次
>>> scipy.__version__
'0.11.0'
>>> np.__version__
'1.6.2'

它完美无缺:

X = np.random.normal(size=(10,4))
V = np.dot(X.transpose(),X)
print V
R = V.copy()
print R
C = scipy.linalg.cholesky(R,False,overwrite_a=True)
print V
print R

输出是:

[[ 11.22274635   5.10611692   0.70263037   3.14603088] # V before
 [  5.10611692   8.94518939  -3.17865941   1.64689675]
 [  0.70263037  -3.17865941   7.35385131  -2.23948391]
 [  3.14603088   1.64689675  -2.23948391   8.25112653]]
[[ 11.22274635   5.10611692   0.70263037   3.14603088] # R before
 [  5.10611692   8.94518939  -3.17865941   1.64689675]
 [  0.70263037  -3.17865941   7.35385131  -2.23948391]
 [  3.14603088   1.64689675  -2.23948391   8.25112653]]
[[ 11.22274635   5.10611692   0.70263037   3.14603088] # V after
 [  5.10611692   8.94518939  -3.17865941   1.64689675]
 [  0.70263037  -3.17865941   7.35385131  -2.23948391]
 [  3.14603088   1.64689675  -2.23948391   8.25112653]]
[[ 3.35003677  1.52419728  0.20973811  0.93910339] # R after
 [ 0.          2.57332704 -1.35946252  0.08375069]
 [ 0.          0.          2.33703292 -0.99382158]
 [ 0.          0.          0.          2.52478036]]

答案 1 :(得分:2)

如果您足够勇敢,可以避免scipy并进行linalg.lapack_lite.dpotrf的低级别电话

import numpy as np

# prepare test data
A = np.random.normal(size=(10,10))
A = np.dot(A,A.T)
L = np.tril(A)

# actual in-place cholesky
assert L.dtype is np.dtype(np.float64)
assert L.flags['C_CONTIGUOUS']
n, m = L.shape
assert n == m
result = np.linalg.lapack_lite.dpotrf('U', n, L, n, 0)
assert result['info'] is 0

# check if L is the desired L cholesky factor
assert np.allclose(np.dot(L,L.T), A)
assert np.allclose(L, np.linalg.cholesky(A))

你必须了解lapack的DPOTRF,fortran调用约定,内存布局。退出时请不要忘记检查result['info'] == 0。尽管如此,你只看到它只是一行代码,并且通过丢弃linalg.cholesky完成的所有健全性检查和复制,这也可能更有效。

答案 2 :(得分:1)

为了完整起见,以下基于Warren评论的代码解决了这个问题:

import numpy
import scipy.linalg

numpy.random.seed(0)
X = numpy.random.normal(size=(10,4))
V = numpy.dot(X.transpose(),X)
R = V.copy('F')
print V.flags['C_CONTIGUOUS']
print R.flags['F_CONTIGUOUS']
scipy.linalg.cholesky(R,False,overwrite_a=True)
print V
print R

我所做的就是将R的基础存储格式从C顺序更改为Fortran顺序,这会导致overwrite_a按预期运行。

如果您的矩阵是真正有价值的,那么只需将转置传递给cholesky即可完成此操作而无需复制。如果你的矩阵是复值的话,我认为转置修正不会起作用,因为复杂的厄米特矩阵的转置通常不等于它的共轭转置。但是,如果您确保您的矩阵首先使用fortran顺序(R.flags['F_CONTIGUOUS'] == True),那么您应该没有问题。但是,请参阅Setting the *default* data order (C vs. Fortran) in Numpy了解该策略的难度。