複数の (ソフト) 制約を持つスパース線形システムを構築しています。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());
=>メモリに優しくない...