scipy 如何在Python中进行Cholesky因子分解

mqkwyuun  于 2022-11-09  发布在  Python
关注(0)|答案(3)|浏览(189)

我尝试做一个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中的一个bug,有没有解决方法或者其他方法可以在Python中进行适当的Cholesky因式分解?

dluptydi

dluptydi1#

再试一次,用

>>> 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]]
ftf50wuq

ftf50wuq2#

如果你足够勇敢,你可以避开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所做的复制,这也会更有效。

o2gm4chl

o2gm4chl3#

为了完整性起见,下面的代码基于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来完成这个操作而不需要复制。我不认为转置修复在你的矩阵是复值的情况下会起作用,因为复Hermitian矩阵的转置通常不等于它的共轭转置。然而,如果你首先确定你的矩阵使用的是fortran order(R.flags['F_CONTIGUOUS'] == True),那么你应该不会有问题。但是,请参阅Setting the default data order (C vs. Fortran) in Numpy了解使用该策略的困难。

相关问题