对称正定矩阵的特征有效逆

时间:2016-07-28 15:22:17

标签: c++ eigen matrix-inverse

在Eigen中,如果我们有对称正定矩阵A,那么我们可以通过

计算A的逆
A.inverse();

A.llt().solve(I);

其中I是与A大小相同的单位矩阵。但有没有更有效的方法来计算对称正定矩阵的逆?

例如,如果我们将A的Cholesky分解为A = LL^{T},那么L^{-T} L^{-1}A的反函数A L^{-T} L^{-1} = LL^{T} L^{-T} L^{-1} = I(以及L^{-T} 1}}表示L)的转置的倒数。

因此我们可以获得A的Cholesky分解,计算其逆,然后获得该逆的叉积以找到A的逆。但我的直觉是,计算这些显式步骤比使用A.llt().solve(I)一样慢。

在任何人问之前,我确实需要一个明确的逆 - 它是对Gibbs采样器的一部分进行计算。

2 个答案:

答案 0 :(得分:3)

使用A.llt().solve(I),您假定A为SPD矩阵并应用Cholesky分解来求解等式Ax=I。求解方程的数学过程与显式方法完全相同。因此,如果您正确地执行每一步,性能应该相同。

另一方面,使用A.inverse(),您正在进行一般矩阵求逆,它使用LU分解大矩阵。因此,性能应低于A.llt().solve(I);

答案 1 :(得分:0)

您应针对特定问题配置代码,以获得最佳答案。在尝试使用googletest库和this repo评估这两种方法的可行性时,我正在对代码进行基准测试:

#include <gtest/gtest.h>

#define private public
#define protected public

#include <kalman/Matrix.hpp>
#include <Eigen/Cholesky>
#include <chrono>
#include <iostream>

using namespace Kalman;
using namespace std::chrono;

typedef float T;
typedef high_resolution_clock Clock;

TEST(Cholesky, inverseTiming) {
    Matrix<T, Dynamic, Dynamic> L;
    Matrix<T, Dynamic, Dynamic> S;
    Matrix<T, Dynamic, Dynamic> Sinv_method1;
    Matrix<T, Dynamic, Dynamic> Sinv_method2;
    int Nmin = 2;
    int Nmax = 128;
    int N(Nmin);

    while (N <= Nmax) {

        L.resize(N, N);
        L.setRandom();
        S.resize(N, N);
        // create a random NxN SPD matrix
        S = L*L.transpose();
        std::cout << "\n";
        std::cout << "+++++++++++++++++++++++++ N = " << N << " +++++++++++++++++++++++++++++++++++++++" << std::endl;
        auto t1 = Clock::now();
        Sinv_method1.resize(N, N);
        Sinv_method1 = S.inverse();
        auto dt1 = Clock::now() - t1;
        std::cout << "Method 1 took " << duration_cast<microseconds>(dt1).count() << " usec" << std::endl;
        auto t2 = Clock::now();
        Sinv_method2.resize(N, N);
        Sinv_method2 = S.llt().solve(Matrix<T, Dynamic, Dynamic>::Identity(N, N));
        auto dt2 = Clock::now() - t2;
        std::cout << "Method 2 took " << duration_cast<microseconds>(dt2).count() << " usec" << std::endl;
        for(int i = 0; i < N; i++)
        {
            for(int j = 0; j < N; j++)
            {
                EXPECT_NEAR( Sinv_method1(i, j), Sinv_method2(i, j), 1e-3 );
            }
        }

        N *= 2;
        std::cout << "+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++" << std::endl;
        std::cout << "\n";
    }
}

以上示例向我展示的是,对于我的身材问题,使用method2可以忽略不计加速,而缺乏准确性(使用.inverse()调用为基准)是显而易见的。