C++ Cholesky 分解
C++ Cholesky factorization
我需要用 C++ 重写一些 MatLab 代码。
在 Matlab 代码中,我们调用函数 chol
来计算上三角矩阵。
对于 C++ 部分,我开始研究 Eigen。
但是,我很难获得与 Matlab 的 chol
函数等效的函数。
我尝试使用 Eigen 的 LDLT
class:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
MatrixXd matA(2, 2);
matA << 1, 2, 3, 4;
MatrixXd matB(4, 4);
matB << matA, matA/10, matA/10, matA;
matB = matB*matB.transpose();
Eigen::LDLT<MatrixXd> tmp(matB);
MatrixXd U = tmp.matrixU();
cout << U << endl;
}
但结果与 Matlab 代码不同:
matB = [ 1 2 0.1 0.2
3 4 0.3 0.4
0.1 0.2 1 2
0.3 0.4 3 4];
matB = matB*matB';
D = chol(matB);
根据 Eigen::LDTL 的文档,第二个模板参数 _UpLo
默认为 Lower
但您省略了该参数并想要计算上三角矩阵。
因此您的 class 实例化应该类似于此(不知道此处正确的 Eigen-define 是否是 Upper
):
Eigen::LDLT<MatrixXd, Upper> tmp(matB);
编辑
@chtz 是对的-使用 Upper
不会给您预期的结果,因为 LDLT
class 用于通过旋转进行稳健的 cholesky 分解。
因此,除了@Avi 的正确答案之外,您还可以使用正确的 class 进行标准的 cholesky 分解:
Eigen::LLT<MatrixXd> tmp(matA);
cout << MatrixXd(tmp.matrixU()) << "\n\n";
使用您的代码示例和 Matlab documentation, I get the same result when using LLT instead of LDLT (online):
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using std::cout;
int main()
{
MatrixXd matA(3,3);
matA << 1, 0, 1, 0, 2, 0, 1, 0, 3;
cout << matA << "\n\n";
Eigen::LDLT<MatrixXd> tmp(matA);
cout << ((tmp.info() == Success) ? "succeeded" : "failed") << "\n\n";
MatrixXd U = tmp.matrixL();
cout << U << "\n\n";
// Using LLT instead
cout << MatrixXd(matA.llt().matrixL()) << "\n\n";
cout << MatrixXd(matA.llt().matrixU()) << "\n\n";
}
输出:
1 0 1
0 2 0
1 0 3
succeeded
1 0 0
0 1 0
0.333333 0 1
1 0 0
0 1.41421 0
1 0 1.41421
1 0 1
0 1.41421 0
0 0 1.41421
我需要用 C++ 重写一些 MatLab 代码。
在 Matlab 代码中,我们调用函数 chol
来计算上三角矩阵。
对于 C++ 部分,我开始研究 Eigen。
但是,我很难获得与 Matlab 的 chol
函数等效的函数。
我尝试使用 Eigen 的 LDLT
class:
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;
int main() {
MatrixXd matA(2, 2);
matA << 1, 2, 3, 4;
MatrixXd matB(4, 4);
matB << matA, matA/10, matA/10, matA;
matB = matB*matB.transpose();
Eigen::LDLT<MatrixXd> tmp(matB);
MatrixXd U = tmp.matrixU();
cout << U << endl;
}
但结果与 Matlab 代码不同:
matB = [ 1 2 0.1 0.2
3 4 0.3 0.4
0.1 0.2 1 2
0.3 0.4 3 4];
matB = matB*matB';
D = chol(matB);
根据 Eigen::LDTL 的文档,第二个模板参数 _UpLo
默认为 Lower
但您省略了该参数并想要计算上三角矩阵。
因此您的 class 实例化应该类似于此(不知道此处正确的 Eigen-define 是否是 Upper
):
Eigen::LDLT<MatrixXd, Upper> tmp(matB);
编辑
@chtz 是对的-使用 Upper
不会给您预期的结果,因为 LDLT
class 用于通过旋转进行稳健的 cholesky 分解。
因此,除了@Avi 的正确答案之外,您还可以使用正确的 class 进行标准的 cholesky 分解:
Eigen::LLT<MatrixXd> tmp(matA);
cout << MatrixXd(tmp.matrixU()) << "\n\n";
使用您的代码示例和 Matlab documentation, I get the same result when using LLT instead of LDLT (online):
#include <iostream>
#include <Eigen/Dense>
using namespace Eigen;
using std::cout;
int main()
{
MatrixXd matA(3,3);
matA << 1, 0, 1, 0, 2, 0, 1, 0, 3;
cout << matA << "\n\n";
Eigen::LDLT<MatrixXd> tmp(matA);
cout << ((tmp.info() == Success) ? "succeeded" : "failed") << "\n\n";
MatrixXd U = tmp.matrixL();
cout << U << "\n\n";
// Using LLT instead
cout << MatrixXd(matA.llt().matrixL()) << "\n\n";
cout << MatrixXd(matA.llt().matrixU()) << "\n\n";
}
输出:
1 0 1
0 2 0
1 0 3succeeded
1 0 0
0 1 0
0.333333 0 11 0 0
0 1.41421 0
1 0 1.414211 0 1
0 1.41421 0
0 0 1.41421