Eigen3.3.7使用SparseLU求解大型稀疏系统触发断言错误问题
首先明确两个错误的根源:
- 运行时断言错误:
void Eigen::PlainObjectBase::resize(Eigen::Index) [with
Derived = Eigen::Matrix<int, -1, 1>; Eigen::Index = long int]:
Assertion ((SizeAtCompileTime == Dynamic &&
(MaxSizeAtCompileTime==Dynamic || size<=MaxSizeAtCompileTime)) ||
SizeAtCompileTime == size) && size>=0' failed.
该错误是因为Eigen 3.3.7版本的COLAMDOrdering默认使用int作为索引存储类型,当矩阵阶数较大、或者在32位编译环境下索引计算溢出时,就会触发resize参数合法性校验失败的断言。你提到的N=98000的场景,如果编译为32位程序也会触发该问题。
- 更换索引类型后的编译错误:
error: no match for call to
‘(Eigen::SparseQREigen::SparseMatrix<std::complex,
Eigen::COLAMDOrdering >::OrderingType {aka
Eigen::COLAMDOrdering}) (const
Eigen::SparseMatrixstd::complex&,
Eigen::SparseQREigen::SparseMatrix<std::complex,
Eigen::COLAMDOrdering >::PermutationType&)’ 315 |
ord(matCpy, m_perm_c);
该错误是因为Eigen 3.3.7的COLAMDOrdering原生只支持int类型的模板参数,直接传入Eigen::Index或long int会导致排序接口和置换矩阵的索引类型不匹配,无法通过编译。
可直接落地的解决方法(按优先级排序)
- 优先级最高:升级Eigen版本到3.4及以上。3.4版本起SparseLU的默认排序逻辑已原生适配
Eigen::Index长索引,无需修改原有代码即可正常运行,改造成本最低。 - 优先级次之:如果必须保留Eigen 3.3.7版本,将SparseLU的排序模板参数替换为
AMDOrdering<Eigen::Index>。AMD排序在3.3.7版本已支持长索引类型,无需修改源码即可直接使用,98000阶的矩阵使用AMD排序的性能损失几乎可以忽略。 - 优先级最低:如果必须使用COLAMD排序且不能升级Eigen版本,手动修改Eigen源码中COLAMD模块的实现,将所有硬编码的
int索引替换为Eigen::Index,重新编译你的项目即可。
临时验证方案
可以先开启64位编译选项,关闭所有32位兼容配置,重新编译运行项目。大部分情况下98000阶的矩阵在64位编译环境下,即使不修改排序参数也可以正常运行,可先通过该方式确认问题根因为索引类型溢出。
内容的提问来源于stack exchange,提问作者Zack Taylor

