在python

时间:2016-01-12 18:06:42

标签: python matrix

我正在使用python 2,我想测试矩阵是否为正半正定(PSD)。 我已经构建了一个随机矩阵X,我想测试Q = X T X的SDP属性。

为此,我调整了一个测试正定性质的函数,以测试正半正定性质。然后我计算我的矩阵Q = X T X. X T X应该是PSD,因为它是矩阵及其转置的乘积(有关PSD保证的更多细节,请参见Is a matrix multiplied with its transpose something special?)。但是,当我测试Q是否为PSD时,函数返回false。

有谁知道我的代码错在哪里?是我的测试功能不测试PSD属性或其他东西?

这是我的脚本(以比实际更简单的方式):

from scipy.stats import bernoulli
from scipy import linalg
import numpy as np

p = 300
N = 100
np.random.seed(18) 
X = bernoulli.rvs(0.5, size=p*N).reshape((N, p))
X = 2 * X - 1* np.ones_like(X)
Q = np.dot(X.T, X)
def is_semi_pos_def(x):
    return np.all(np.linalg.eigvals(x) >= 0)
is_semi_pos_def(Q)

它返回:

False

非常感谢您对此的任何帮助。

1 个答案:

答案 0 :(得分:3)

由于你在脚本中创建的矩阵Q没有满等级,如果N< p,一些特征值将为0.但是正如评论中所提到的,np.eigvals中的数值误差导致它们变为负数:

P = 5
N = 3
np.random.seed(18) 
X = bernoulli.rvs(0.5, size=N*P).reshape((N, P))
X = 2 * X - 1* np.ones_like(X)
Q = np.dot(X.T, X)
np.linalg.eigvals(Q)

返回

[1.24244289e+01,  -2.96746135e-16,   2.57557110e+00, 4.23704588e-33,   4.25752762e-18]

您可以通过仅测试特征值是否大于0-E来解释错误,对于某些适当小的E>但是,如果在实践中你知道你的矩阵将是满级,你可以计算Cholesky decomposition这似乎是使用numpy的最快方法。

import numpy as np

P = 300
N = 100
X = bernoulli.rvs(0.5, size=N*P).reshape((N, P))
X = 2 * X - 1* np.ones_like(X)
Q = np.dot(X.T, X)

@timing
def is_semi_pos_def_chol(x):
    try:
        np.linalg.cholesky(x)
        return True
    except np.linalg.linalg.LinAlgError:
        return False

@timing
def is_semi_pos_def_eigsh(x, epsilon=1e-10):
    return np.all(np.linalg.eigvalsh(x) >= -epsilon)

@timing
def is_semi_pos_def_eigs(x, epsilon=1e-10):
    return np.all(np.linalg.eigvals(x) >= -epsilon)

print is_semi_pos_def(Q)
print is_semi_pos_def_eigs(Q)
print is_semi_pos_def_eigsh(Q)

返回:

is_semi_pos_def function took 0.001 s
False
is_semi_pos_def_eigs function took 0.073 s
True
is_semi_pos_def_eigsh function took 0.011 s
True

我们可以使用更快的eigvalsh,因为矩阵是对称的。 请注意,由于Q的非平凡内核,Cholesky分解错误地返回False。但是对于N = P = 300,这不是问题:

is_semi_pos_def_chol function took 0.002 s
True
is_semi_pos_def_eigs function took 0.118 s
True
is_semi_pos_def_eigsh function took 0.023 s
True

如果你想要一个分析上合理的答案,你可以使用sympy来计算没有数值误差的特征值,或者使用sympy计算Cholesky分解,这也可以避免浮点错误。然而,对于大的N和P,计算时间变得过高:

from sympy.mpmath import mp

P = 30
N = 10
X = bernoulli.rvs(0.5, size=N*P).reshape((N, P))
X = 2 * X - 1* np.ones_like(X)
M = Matrix(np.dot(X.T, X))
Q = np.dot(X.T, X)


@timing
def is_semi_pos_def_symbolic(x):
    try:
        M.cholesky()
        return True
    except ValueError as e:
        print e
        return False

print is_semi_pos_def_symbolic(M)
print is_semi_pos_def_chol(Q)
print is_semi_pos_def_eigsh(Q)

注意分析真相的重大代价:

is_semi_pos_def_symbolic function took 0.908 s
True
is_semi_pos_def_chol function took 0.000 s
False
is_semi_pos_def_eigsh function took 0.000 s
True