对本征QR分解感到困惑

时间:2019-05-08 19:06:09

标签: c++ linear-algebra eigen eigen3 eigenvalue

我对本征的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;尽管一列是正确的而另一列是错误的。

1 个答案:

答案 0 :(得分:0)

正如@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)。