我正在编写一些涉及查找给定矩阵的特征向量的代码,并且很惊讶Ruby在简单的情况下会产生一些不合理的结果。
例如,以下矩阵具有与特征值1相关联的特征向量:
> m = Matrix[[0r, 1/2r, 1/2r, 1/3r],
[0r, 0r, 1/4r, 1/3r],
[0r, 1/4r, 0r, 1/3r],
[1r, 1/4r, 1/4r, 0r]]
Ruby发现特征值足够好,但特征向量爆炸:
> m.eigen.eigenvalues[2]
=> 1.0000000000000009
m.eigen.eigenvectors[2]
=> Vector[5.957702309312754e+15, 5.957702309312748e+15, 5.957702309312743e+15, 5.957702309312753e+15]
实际的特征向量应为(7,4,4,9)。
这不是麻烦吗?如果Ruby无法处理微小的矩阵,那么我们怎么能相信呢?或者我做错了什么?
不,这不是麻烦。该矩阵可能对该特定的特征向量算法实现不起作用。毕竟,Efficient and stable general eigenvector computation is nontrivial。
Matrix
库改编自JAMA, a Java matrix package,它说它有numerical computation而不是symbolic computation:
不包括。 JAMA绝不是一个完整的线性代数环境......它侧重于数值线性代数所需的原理数学功能
查看Matrix::EigenvalueDecomposition
的源代码,我发现它命名为QR algorithm的用法。我不完全理解数学的复杂性,但我想我可能理解为什么这个计算失败了。计算机制如前所述:
在第k步(从k = 0开始),我们计算QR分解Ak = QkRk ...在某些条件下,[4]矩阵Ak收敛到三角矩阵,Schur形式为A.特征值在对角线上列出三角矩阵,求解特征值问题。
在“伪”Ruby中,这在概念上意味着:
working_matrix = orig_matrix.dup
all_q_matrices = []
loop do
q, r = working_matrix.qr_decomposition
all_q_matrices << q
next_matrix = r * q
break if difference_between(working_matrix, next_matrix) < accuracy_threshold
end
eigenvalues = working_matrix.diagonal_values
对于特征向量,它继续:
在收敛时,AQ =QΛ,其中Λ是A收敛的特征值的对角矩阵,并且其中Q是到达那里所需的所有正交相似变换的合成。因此,Q列是特征向量。
在“伪”Ruby中,继续:
eigenvectors = all_q_matrices.inject(:*).columns
我们可以看到,数值计算的迭代被用来计算近似的特征值,并且作为副作用,收集了一堆近似的Q
矩阵。然后,这些近似的Q
矩阵组合在一起形成特征向量。
近似的复合可能导致非常不准确的结果。 Math StackExchange上的灾难性取消示例显示了simple quadratic computation with 400% relative error。您可能会想象具有重复算术运算的迭代矩阵算法如何能够做得更糟。
一粒盐
同样,我对算法的数学和实现没有深刻的理解,所以我不知道计算的哪些部分导致了你的具体85110032990182200%错误,但我希望你现在能够理解它是如何产生的发生了。