我对 Eigen 的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;尽管一列是正确的而另一列是错误的。
  • 最佳答案

    正如@geza所指出的,QR分解的R矩阵将(通常)不包含原始矩阵的特征值,如果是这种情况,生活将非常容易:)

    对于另一个问题,如果要从AQ重构R,则只需查看QR.matrixQR()的上三角部分

    Eigen::Matrix<Real, Eigen::Dynamic, Eigen::Dynamic>
                  R = QR.matrixQR().triangularView<Eigen::Upper>();
    

    除此之外,我建议在将auto与表达式模板结合使用时要格外小心(在您的情况下,这没有什么大错,除了Rdiag至少被评估了两次)。

    而且,在现代CPU上使用long double几乎不是一个好主意。首先,请确保您使用的算法在数值上是稳定的,并且如果确实存在精度问题,请考虑使用任意精度浮点数(例如MPFR)。

    10-07 23:47