EIGEN 3.3.4中RowMajor存储SparseMatrix求逆及求解器适配问题
搞定Eigen 3.3.4里RowMajor稀疏矩阵求逆的坑
最近帮朋友排查了Eigen中RowMajor稀疏矩阵求逆的问题,正好和你遇到的情况一模一样,给你梳理下问题根源和解决办法:
你遇到的两个核心问题解析
RowMajor矩阵用SimplicialLDLT求解返回Solve对象无法转换
SimplicialLDLT这个求解器本质是为ColMajor对称矩阵设计的,它的solve()方法返回的是延迟计算的Solve代理对象,直接转RowMajor矩阵会触发THIS_METHOD_IS_ONLY_FOR_COLUMN_MAJOR_MATRICES错误——这是因为内部实现只兼容ColMajor的存储逻辑。切换ColMajor求解器后得到错误的逆矩阵
这才是关键!SimplicialLDLT仅适用于对称正定矩阵,但你的矩阵A是下三角矩阵(不对称,第一行第二列是-1,第二行第一列是0),用这个求解器相当于强行按对称矩阵处理,自然得到错误的单位矩阵结果。
正确解决方案:换用SparseLU求解器
SparseLU是Eigen专门为非对称稀疏矩阵设计的直接求解器,完美支持RowMajor存储格式,能正确处理你的矩阵。
给你贴个可直接运行的完整代码:
#include <Eigen/Sparse> #include <iostream> int main() { // 初始化RowMajor稀疏矩阵A Eigen::SparseMatrix<short, Eigen::RowMajor> A(3, 3); A.insert(0, 0) = 1; A.insert(0, 1) = -1; A.insert(1, 1) = 1; A.insert(2, 2) = 1; A.makeCompressed(); // 压缩矩阵提升求解效率 // 创建RowMajor单位矩阵I Eigen::SparseMatrix<short, Eigen::RowMajor> identity(A.rows(), A.cols()); identity.setIdentity(); // 使用SparseLU求解器,支持RowMajor和非对称矩阵 Eigen::SparseLU<Eigen::SparseMatrix<short, Eigen::RowMajor>> solver; solver.compute(A); // 检查矩阵分解是否成功(避免奇异矩阵) if (solver.info() != Eigen::Success) { std::cerr << "矩阵分解失败,可能是奇异矩阵!" << std::endl; return 1; } // 求解Ax=I,直接得到RowMajor的稀疏逆矩阵 Eigen::SparseMatrix<short, Eigen::RowMajor> inverse = solver.solve(identity); // 输出结果验证 std::cout << "预期逆矩阵:\n1 1 0\n0 1 0\n0 0 1\n" << std::endl; std::cout << "实际计算结果(非零元素):" << std::endl; for (int k = 0; k < inverse.outerSize(); ++k) { for (Eigen::SparseMatrix<short, Eigen::RowMajor>::InnerIterator it(inverse, k); it; ++it) { std::cout << "(" << it.row() << "," << it.col() << ") = " << it.value() << " "; } std::cout << std::endl; } return 0; }
额外注意点
- 一定要调用
makeCompressed():稀疏矩阵在插入元素后是未压缩状态,求解前压缩能大幅提升效率 - 加入求解器状态检查:如果矩阵是奇异的(不可逆),
solver.compute()会失败,提前检查能避免程序崩溃 - 稀疏矩阵输出:直接
cout << inverse可能看不到完整结果,遍历非零元素是更可靠的方式
内容的提问来源于stack exchange,提问作者Spazz
相关产品推荐
相关产品推荐

