8

複数の (ソフト) 制約を持つスパース線形システムを構築しています。boost::ublas を使用してマトリックスを構築するために使用されるコードを Eigen に変換しています。boost:ublas には、既知の (または推定された) ゼロ以外の数を持つスパース行列を作成する便利な方法があり、その要素を更新するためのかなり高速な operator(int row, int col) があります。

問題は次のとおりです。

  • SparseMatrix::setFromTriplets の使用:
    私のシステムには多くの制約があります。素朴で「少し」誇張された例として、500 nnz で 10 億の冗長な制約がある 100x100 疎行列があるとします (つまり、非ゼロ係数は 10 億回変更されます)。setFromTriplets では、10 億個の係数を格納する必要があり、そのほとんどが合計されて、500 個の非ゼロ係数のセットが形成されます。それは本当に効率的でもメモリフレンドリーでもありません。もちろん、std::vector を std::map に置き換えて、制約の累積を手動で実行することもできますが、これではどうにか疎行列クラスを持つという点が失われ、効率的でもありません。

  • 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());

=>メモリに優しくない...

4

1 に答える 1

7

を効率的にするinsertには、各列のゼロ以外の推定数を含む を使用しcoeffRefて十分なスペースを予約する必要があります。多数の再割り当て/コピーを避けるために、これらの数を少し過大評価することをお勧めします。もう 1 つの補完的なトリックは、最初に要素にアクセスするときに、この要素が列の最後の要素になるようにすることです。mat.reserve(nnz)nnzEigen::VectorXi(i,j)j

スパース パターンを簡単に計算できる場合、別の方法として、一意のトリプレットのベクトルを値として 0 で埋めると、coeffRef が高速になります。

于 2013-08-10T08:45:38.927 に答える