我正在建立一个具有多个(软)约束的稀疏线性系统。我正在将一些用于通过boost::ublas构建矩阵的代码转换为Eigen。 boost:ublas提供了一种方便的方法来创建具有已知(或估计的)非零数量的稀疏矩阵,并且具有相当快的运算符(int row,int col)来更新其元素。

问题如下:

  • 使用SparseMatrix::setFromTriplets:
    我的系统有很多限制。作为一个天真的,``略微''的夸张示例,假设我有一个100x100的稀疏矩阵,具有500 nnz但有10亿个冗余约束(即,非零系数被修改了十亿次)。 setFromTriplets需要我存储10亿个系数,其中大部分将加起来形成我的500个非零系数集。那不是很有效,也不是内存友好的。
    当然,我可以用std::map替换我的std::vector,并手动执行约束的累加,但这在某种程度上错过了拥有稀疏矩阵类的要点,这也不是很有效。
  • 使用SparseMatrix::insert(i,j,val):
    如果该元素已经存在,则不起作用。我的问题是要能够累积已经存在的系数。
  • 使用SparseMatrix::coeffRef(i,j)的
  • :
    那确实有效,并且将是我正在寻找的功能。但是,它比boost::ublas慢几个数量级。令我惊讶的是,我没有看到更好的功能。
    我认为这是由于预先未知的非零数导致的,并迫使进行多次重新分配(实际上是这样)。但是,使用SparseMatrix::reserve()无效,因为它是仅适用于压缩矩阵的函数(在断言之前,源中的注释说“在非压缩模式下此函数没有意义”)。 ..并且,如文档所述:“将新元素插入SparseMatrix会将其稍后转换为未压缩模式”。

  • 在Eigen中构建稀疏矩阵同时仍然能够多次更新其系数的最有效方法是什么?

    谢谢

    [编辑:示例用例:具有10个非零的10x10矩阵。为简单起见,矩阵是对角线]
    SparseMatrix<double> mat(10, 10);
    for (int i=0; i<10; i++) {
      for (int j=0; j<1000000; j++) {
        mat.coeffRef(i, i) += rand()%10;
      }
    }
    

    =>可以工作,但是比ublas operator()慢几个数量级(当然,对于更大的矩阵和更实际的设置)。
    std::vector<Eigen::Triplet<double> > triplets(10000000);
    int k=0;
    for (int i=0; i<10; i++) {
      for (int j=0; j<1000000; j++) {
        triplets[k++] = Eigen::Triplet<double>(i,i,rand()%10);
      }
    }
    SparseMatrix<double> mat(10, 10);
    mat.setFromTriplets(triplets.begin(), triplets.end());
    

    =>对内存不友好...

    最佳答案

    为了使insertcoeffRef高效,您需要使用mat.reserve(nnz)保留足够的空间,其中nnz是一个Eigen::VectorXi,其中包含每列非零的估计数量。最好稍微高估这些数字,以避免大量的重新分配/拷贝。另一个补充技巧是确保您首次访问(i,j)元素时,此元素是j列的最后一个元素。

    如果您可以轻松地计算稀疏模式,那么另一种方法是用值的0填充唯一三元组的 vector ,然后coeffRef将很快。

    09-08 04:58