我对本征的QR分解感到困惑。我的理解是,矩阵Q
被隐式存储为Householder变换的序列,矩阵R
被存储为上三角矩阵,R
的对角线包含A
的特征值(至少直到相位,这是我关心的全部)。
但是,我编写了以下程序,该程序通过两种不同的方法来计算矩阵A
的特征值,一种使用Eigen::EigenSolver
,另一种使用QR
。我知道我的QR
方法返回错误的结果,并且EigenSolver
方法返回正确的结果。
我在这里误会什么?
#include <iostream>
#include <algorithm>
#include <Eigen/Dense>
int main()
{
using Real = long double;
long n = 2;
Eigen::Matrix<Real, Eigen::Dynamic, Eigen::Dynamic> A(n,n);
for(long i = 0; i < n; ++i) {
for (long j = 0; j < n; ++j) {
A(i,j) = Real(1)/Real(i+j+1);
}
}
auto QR = A.householderQr();
auto Rdiag = QR.matrixQR().diagonal().cwiseAbs();
auto [min, max] = std::minmax_element(Rdiag.begin(), Rdiag.end());
std::cout << "\u03BA\u2082(A) = " << (*max)/(*min) << "\n";
std::cout << "\u2016A\u2016\u2082 via QR = " << (*max) << "\n";
std::cout << "Diagonal of R =\n" << Rdiag << "\n";
// dblcheck:
Eigen::SelfAdjointEigenSolver<decltype(A)> eigensolver(A);
if (eigensolver.info() != Eigen::Success) {
std::cout << "Something went wrong.\n";
return 1;
}
auto absolute_eigs = eigensolver.eigenvalues().cwiseAbs();
auto [min1, max1] = std::minmax_element(absolute_eigs.begin(), absolute_eigs.end());
std::cout << "\u03BA\u2082(A) via eigensolver = " << (*max1)/(*min1) << "\n";
std::cout << "\u2016A\u2016\u2082 via eigensolver = " << (*max1) << "\n";
std::cout << "The absolute eigenvalues of A via eigensolver are:\n" << absolute_eigs << "\n";
}
输出:
κ₂(A) = 15
‖A‖₂ via QR = 1.11803
Diagonal of R =
1.11803
0.0745356
κ₂(A) via eigensolver = 19.2815
‖A‖₂ via eigensolver = 1.26759
The absolute eigenvalues of A via eigensolver are:
0.0657415
1.26759
其他信息:
$ hg log | more
changeset: 11993:20cbc6576426
tag: tip
date: Tue May 07 16:44:55 2019 -0700
summary: Fix AVX512 & GCC 6.3 compilation
在使用g ++-8,g ++-9和Apple Clang进行编译时(带有和不带有-ffast-math
时出现)。我用Eigen::FullPivHouseholderQR
得到了同样的错误结果。
我还查看了源HouseholderQR.h
,他们通过m_qr.diagonal().prod()
计算了行列式,这使我对自己正确使用API感到更有信心。从EigenSolver中获取特征值的乘积将返回与QR.absDeterminant()
相同的值。
以下代码段不返回原始矩阵A :
Eigen::Matrix<Real, Eigen::Dynamic, Eigen::Dynamic> R = QR.matrixQR();
Eigen::Matrix<Real, Eigen::Dynamic, Eigen::Dynamic> Q = QR.householderQ();
std::cout << "Q*R = \n" << Q*R << "\n";
我检查了Q
是否具有所有必需的属性:Q ^ -1 = Q ^ T,Q ^ TQ = I和| det(Q)| = 1。
我还验证了QR.householderQ().transpose()*QR.matrixQR()
不等于A
;尽管一列是正确的而另一列是错误的。
答案 0 :(得分:0)
正如@geza所指出的,QR分解的R
矩阵将(通常)不包含原始矩阵的特征值,如果真是这样,生活将会很容易:)
对于另一个问题,如果要从A
和Q
重建R
,则只需查看QR.matrixQR()
的上三角部分
Eigen::Matrix<Real, Eigen::Dynamic, Eigen::Dynamic>
R = QR.matrixQR().triangularView<Eigen::Upper>();
除此之外,我建议将auto
与表达式模板结合使用时要小心(在您的情况下,没有什么大错,除非Rdiag
至少被评估两次)。
此外,在现代CPU上使用long double
也不是一个好主意。首先,请确保您使用的算法在数值上是稳定的,并且如果确实存在精度问题,请考虑使用任意精度浮点数(如MPFR)。