伪随机正定矩阵的生成 我想测试一个简单的Cholesky代码,我用C++编写的。所以我生成一个随机的下三角L,然后乘以它的转置,生成a A = L * Lt;
但是我的代码没有因子A。所以我在Matlab中尝试了这个:伪随机正定矩阵的生成 我想测试一个简单的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在第一个代码中是下三角
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