生成一个 pseduo-随机正定矩阵
generating a pseduo-random positive definite matrix
我想测试我用C++写的一个简单的Cholesky代码。所以我正在生成一个随机的下三角形 L 并乘以它的转置以生成 A。
A = L * Lt;
但是我的代码无法考虑 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 在第一个代码中是下三角形的,而不是第二个代码。为什么这很重要?
在阅读了生成正半定矩阵的简单算法后,我还尝试了以下内容:
from scipy import random, linalg
A = random.rand(100, 100)
B = A*A.transpose()
linalg.cholesky(B)
但它错误如下:
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
我不明白为什么scipy会发生这种情况。有什么想法吗?
谢谢
尼莱什。
问题不在于 cholesky 因式分解。问题出在随机矩阵L
. rand(N,N)
的条件比tril(rand(N,N))
好得多。要看到这一点,请将cond(rand(N,N))
与cond(tril(rand(N,N)))
进行比较。我得到了第一个矩阵的1e3
和第二个矩阵的1e19
,所以第二个矩阵的条件数要高得多,计算在数值上会不太稳定。这将导致在条件不佳的情况下获得一些小的负特征值 - 要使用eig()
查看特征值,一些小的特征值将是负的。
所以我建议使用 rand(N,N)
来生成一个数值稳定的随机矩阵。
顺便说一句,如果您对为什么会发生这种情况的理论感兴趣,可以看看这篇论文:
http://epubs.siam.org/doi/abs/10.1137/S0895479896312869
如前所述,三角矩阵的特征值位于对角线上。因此,通过做
L=tril(rand(n))
您确保 eig(L( 仅产生正值。您可以通过在对角线上添加足够大的正数来改善 L*L' 的条件数,例如
L=L+n*eye(n)
L*L' 是正定的,条件良好:
> cond(L*L')
ans =
1.8400
要在 MATLAB 中生成随机正定矩阵,您的代码应为:
N=200;
L=rand(N, N);
A=L*transpose(L);
[lc,p]=chol(A,'lower');
eig(A)
p
而且您确实应该让特征值大于零,p
为零。
你问的是下三角形的情况。让我们看看会发生什么,以及为什么会有问题。这通常是一件好事,看看测试用例。
对于简单的 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行列式的分布会有所帮助。更好的是考虑log(det(L((的分布。由于行列式只是对角元素的乘积,因此对数是对角元素的对数之和。(是的,我知道行列式是奇点的糟糕度量,但是log(det(L((的分布很容易计算,我觉得懒得考虑条件数的分布。
啊,但是均匀随机变量的负对数是指数变量,在这种情况下是 lambda = 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
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- 为什么 Serial.println(<char[]>);返回随机字符?
- 字符串-C++后显示的随机字符
- 循环中的随机函数
- 在c++构造函数中使用随机字符串生成器
- 使用std::mt19937从字符串中返回一个随机单词
- 为什么std::condition_variable notify_all的工作速度比notify_one快(对于随机请
- 如何在C++中高效地构造随机骰子
- 在类中使用随机生成器时出现性能问题
- 在将数字随机生成为数组期间从内存输出随机数的数组
- 将字符随机转换为大写的函数
- 为什么 vector 的随机访问迭代器给出与指针不同的内存地址?
- 如何生成一个随机的 n 位数,其中 n 是任意的
- 将随机生成的数字添加到数组 + 对这些数组求平均值
- 如何使用要传递给 mt19937 的可选随机种子参数设计函数
- 在C++中随机生成 20 个非重复数字
- GCC:随机构建导致执行期间分段错误
- 如何使用 SML 随机生成八进制元组
- 当我尝试使用它时,Scanf 会抛出一个随机异常(scanf_s 也是如此)
- 生成一个 pseduo-随机正定矩阵