Eigen使用稀疏b向量调用solveWithGuess迭代求解线性系统报错
接口限制的原因
Eigen 3.4.x版本的BiCGSTAB求解器中,solve()和solveWithGuess()的接口实现逻辑不同:
solve()方法针对稀疏右侧向量b做了专门的重载,会自动完成稀疏到稠密的隐式转换,再送入迭代逻辑solveWithGuess()在3.4版本没有做稀疏输入的兼容设计,仅支持传入派生自Eigen::VectorBase的稠密向量类型,稀疏向量属于Eigen::SparseVectorBase类型,无法匹配函数签名,因此报调用错误。
之所以有这个设计差异,核心是因为迭代求解的所有核心计算步骤(残差计算、内积、预条件器作用、向量更新)都基于稠密向量实现,哪怕输入的b或x0是稀疏格式,迭代过程中所有中间变量也都是稠密的,3.4版本的开发团队认为给solveWithGuess额外加稀疏重载的收益极低,因此没有做对应的适配。
你测试中solver.solveWithGuess(dv, sv);可以正常运行,本质是编译器自动把稀疏的x0隐式转换为了稠密向量,并非原生支持稀疏输入。
优化解决方案
1. 优先升级Eigen版本
Eigen 3.5及以上稳定版本已经补全了solveWithGuess的稀疏输入重载,可以直接传入稀疏格式的b和x0,不需要修改现有业务逻辑,是成本最低的优化方案。
2. 3.4版本下的低开销适配
如果受环境限制必须使用Eigen 3.4版本,不需要调整求解逻辑,只要减少不必要的稀疏/稠密格式互转即可降低开销,参考写法:
Eigen::SparseMatrix<double> A; Eigen::SparseVector<double> b; Eigen::SparseVector<double> x0; Eigen::BiCGSTAB<SparseMat, Eigen::IncompleteLUT<double>> solver; solver.compute(A); // 仅做两次稀疏转稠密操作,迭代全程使用稠密向量减少转换开销 Eigen::VectorXd dense_b(b); Eigen::VectorXd dense_x0(x0); Eigen::VectorXd dense_x = solver.solveWithGuess(dense_b, dense_x0); // 仅当下游逻辑必须使用稀疏格式的x时再做转换,否则直接使用dense_x即可 Eigen::SparseVector<double> x = dense_x.sparseView();
这种写法的额外开销仅为两次O(n)的格式转换,和迭代求解本身的计算开销相比几乎可以忽略,你之前感知到的效率低大概率是多次隐式格式转换导致的,按上述写法减少转换次数后性能不会有明显损失。
3. 自定义接口扩展(不推荐)
如果确实需要原生支持稀疏输入,可以参考Eigen源码中solve()的稀疏重载实现,自行给BiCGSTAB类扩展支持稀疏输入的solveWithGuess方法,但是该方案需要修改Eigen源码,后续升级版本时需要重新适配,性价比极低。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

