从较小的稀疏矩阵中组装eigen3稀疏矩阵

时间:2017-12-11 09:12:35

标签: sparse-matrix eigen

我正在组装耦合多物理系统的雅可比。雅可比由每个系统的对角线上的块矩阵和耦合的对角线块组成。 我发现最好组装成分离块,然后用投影矩阵对它们求和以获得完整的雅可比。 伪代码(其中J [i]是对角元素,C [ij]是耦合,P是完整矩阵的投影)。

// diagonal blocks
J.setZero();
for(int i=0;i<N;++i){
    J+=P[i]J[i]P[i].transpose()
}
// off diagonal elements
for(int i=0;i<N;++i){
    for(int j=i+1;j<N;++j){
        J+=P[i]C[ij]P[j].transpose()
        J+=P[j]C[ji]P[i].transpose()
    }
}

这需要很多性能,大约占整个程序的20%,这对于某些组装来说太多了。由于系统是高度非线性的,我必须每次重新计算jacobian。 Valgrind表示资源消耗方法是Eigen::internal::assign_sparse_to_sparse,并且在此方法中调用Eigen::SparseMatrix<>::InsertBackByOuterInner

有没有更有效的方法来组装这样的矩阵?

(我还必须使用P *(J P.transpose())而不是P J * J.transpose()来使程序编译,可能已经出现了问题)

P.S:NDEBUG和优化已开启

编辑:通过将P.transpose存储在一个额外的矩阵中,我获得了更好的性能,但总和仍占该程序的15%

1 个答案:

答案 0 :(得分:1)

通过在线工作,您的代码会更快。首先,估算最终矩阵和预留空间中每列的非零数(如果尚未完成):

int nnz_per_col = ...;
J.reserve(VectorXi::Constant(n_cols, nnz_per_col));

如果每列的nnz数量非常不均匀,那么您也可以按列计算:

VectorXi nnz_per_col(n_cols);
for each j
  nnz_per_col(j) = ...;
J.reserve(nnz_per_col);

然后手动插入元素:

for each block B[k]
  for each elements i,j
    J.coeffRef(foo(i),foo(j)) += B[k](i,j)

其中foo实现适当的索引映射。

对于下一次迭代,不需要保留,但是你需要在保留结构的同时将系数值设置为零:

J.coeffs().setZero();