伪随机正定矩阵的生成 我想测试一个简单的Cholesky代码,我用C++编写的。所以我生成一个随机的下三角L,然后乘以它的转置,生成a A = L * Lt;

伪随机正定矩阵的生成 我想测试一个简单的Cholesky代码,我用C++编写的。所以我生成一个随机的下三角L,然后乘以它的转置,生成a A = L * Lt;,c++,matlab,math,matrix,scipy,C++,Matlab,Math,Matrix,Scipy,但是我的代码没有因子A。所以我在Matlab中尝试了这个: N=200; L=tril(rand(N, N)); A=L*L'; [lc,p]=chol(A,'lower'); p 这将输出非零的p,这意味着Matlab也无法计算因子A。我猜随机性会生成秩亏矩阵。我说得对吗 更新: 我忘了提及以下Matlab代码,正如Malife在下面指出的那样: N=200; L=rand(N, N); A=L*L'; [lc,p]=chol(A,'lower'); p 不同的是,L在第一个代码中是下三角

但是我的代码没有因子A。所以我在Matlab中尝试了这个:

N=200; L=tril(rand(N, N)); A=L*L'; [lc,p]=chol(A,'lower'); p
这将输出非零的p,这意味着Matlab也无法计算因子A。我猜随机性会生成秩亏矩阵。我说得对吗

更新:

我忘了提及以下Matlab代码,正如Malife在下面指出的那样:

N=200; L=rand(N, N); A=L*L'; [lc,p]=chol(A,'lower'); p
不同的是,L在第一个代码中是下三角的,而不是第二个代码。这有什么关系

阅读后,我还使用scipy尝试了以下内容:

但它的错误在于:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/dist-packages/scipy/linalg/decomp_cholesky.py", line 66, in cholesky
    c, lower = _cholesky(a, lower=lower, overwrite_a=overwrite_a, clean=True)
  File "/usr/lib/python2.7/dist-packages/scipy/linalg/decomp_cholesky.py", line 24, in _cholesky
    raise LinAlgError("%d-th leading minor not positive definite" % info)
numpy.linalg.linalg.LinAlgError: 2-th leading minor not positive definite
回溯(最近一次呼叫最后一次):
文件“”,第1行,在
文件“/usr/lib/python2.7/dist packages/scipy/linalg/decomp_cholesky.py”,第66行,cholesky
c、 lower=\u cholesky(a,lower=lower,overwrite\u a=overwrite\u a,clean=True)
文件“/usr/lib/python2.7/dist-packages/scipy/linalg/decomp\u cholesky.py”,第24行,in\u cholesky
raise LINALGEROR(“%d-th前导小调非正定”%info)
numpy.linalg.linalg.linalg错误:第2个前导小调非正定
我不明白为什么这会发生在scipy身上。有什么想法吗

谢谢,

Nilesh.

要在MATLAB中生成随机正定矩阵,您的代码应为:

N=200;
L=rand(N, N); 
A=L*transpose(L); 
[lc,p]=chol(A,'lower');
eig(A)
p

你确实应该让特征值大于零并且
p
为零。

问题不在于cholesky分解。问题在于随机矩阵
L
rand(N,N)
tril(rand(N,N))
条件好得多。要了解这一点,请将
cond(rand(N,N))
cond(tril(rand(N,N)))
进行比较。对于第一个矩阵,我得到了类似于
1e3
的结果,对于第二个矩阵,我得到了类似于
1e19
的结果,因此第二个矩阵的条件数要高得多,并且计算在数值上不太稳定。 这将导致在病态情况下获得一些较小的负特征值-要查看使用
eig()
查看特征值的过程,一些较小的特征值将为负

所以我建议使用
rand(N,N)
来生成一个数值稳定的随机矩阵

顺便说一句,如果你对为什么会发生这种情况的理论感兴趣,你可以看看这篇文章:


您询问下三角格的情况。让我们看看发生了什么,为什么会有问题。这通常是一件好事,看看测试用例

对于简单的5x5矩阵

L = tril(rand(5))
L =
      0.72194            0            0            0            0
     0.027804      0.78422            0            0            0
      0.26607     0.097189      0.77554            0            0
      0.96157      0.71437      0.98738      0.66828            0
     0.024571     0.046486      0.94515      0.38009     0.087634

eig(L)
ans =
     0.087634
      0.66828
      0.77554
      0.78422
      0.72194
当然,三角形矩阵的特征值只是对角线元素。由于rand生成的元素总是介于0和1之间,因此它们的平均值大约为1/2。也许研究L行列式的分布会有所帮助。最好是考虑日志(DET(L))的分布。因为行列式只是对角线元素的乘积,所以对数是对角线元素的对数之和。(是的,我知道行列式不能很好地度量奇点,但是log(det(L))的分布很容易计算,我觉得太懒了,不想考虑条件数的分布。)

但是均匀随机变量的负对数是一个指数变量,在这种情况下是一个λ=1的指数。根据中心极限定理,区间(0,1)内n个均匀随机数的对数之和为高斯分布。该总和的平均值为-n。因此,由这种格式生成的下三角nxn矩阵的行列式为exp(-n)。当n为200时,MATLAB告诉我

exp(-200)
ans =
   1.3839e-87
因此,对于任何可感知大小的矩阵,我们可以看到它的条件都很差。更糟糕的是,当你形成乘积L*L'时,它通常在数字上是单数的。相同的参数适用于条件编号。因此,即使对于20x20矩阵,也可以看到这样一个下三角矩阵的条件数相当大。然后当我们形成矩阵L*L'时,条件将按预期平方

L = tril(rand(20));

cond(L)
ans =
   1.9066e+07

cond(L*L')
ans =
   3.6325e+14
看看一个完整的矩阵有多好

A = rand(20);

cond(A)
ans =
       253.74

cond(A*A')
ans =
        64384

如前所述,三角形矩阵的特征值位于对角线上。因此,

L=tril(rand(n))
您确保eig(L)只产生正值。您可以通过在对角线上添加足够大的正数来改进L*L'的条件数,例如

L=L+n*eye(n)
L*L'是正定的且条件良好:

> cond(L*L')

ans =

1.8400

是的,我忘了在原来的问题中提到这一点,现在更新了。谢谢但是我不明白为什么在第一个Matlab代码示例中,如果L是下三角形,A就不能分解?太好了!我没有想到这一点,所以尽管算法本身是稳定的,但病态的数据导致了问题。这篇文章描述了一个非常有趣的现象,不过我需要更多的背景知识才能完全理解它。谢谢另一个问题是,第二种方法(rand(N,N))是否可证明生成SPD矩阵?我认为它生成秩亏矩阵的可能性(非常小)。有什么想法吗?虽然我不知道SciPy是怎么回事,生成的随机矩阵(1e3)的条件数似乎还可以。事实上,很容易看出,使用第二种方法,仍然可以得到病态矩阵和负特征值。因为它生成一个随机矩阵,你基本上可以得到任何矩阵(0,1以内),包括病态矩阵,特别是你可以得到与tril(rand(N,N))给出的矩阵非常相似的矩阵(概率很小)。例如:矩阵tril(rand(200200))+0.0001可能由rand(200200)生成,但将是病态的。在numpy(scipy使用)中,数组与
*
的乘法是按元素计算的,而不是代数计算的。对于代数积,使用
dot
函数。所以你应该写
B=dot(A,A.transpose())
,或者<
> cond(L*L')

ans =

1.8400