在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采样器的一部分进行计算。
答案 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()
调用为基准)是显而易见的。