我需要设置Eigen::SparseMatrix
的稀疏模式,我已经知道(我有唯一的排序列索引和行偏移量)。显然,通过setFromTriplets
是可能的,但不幸的是,setFromTriplets
需要大量额外的内存(至少在我的情况下是这样)。
我写的小例子
const long nRows = 5000000;
const long nCols = 100000;
const long nCols2Skip = 1000;
//It's quite big!
const long nTriplets2Reserve = nRows * (nCols / nCols2Skip) * 1.1;
Eigen::SparseMatrix<double, Eigen::RowMajor, long> mat(nRows, nCols);
std::vector<Eigen::Triplet<double, long>> triplets;
triplets.reserve(nTriplets2Reserve);
for(long row = 0; row < nRows; ++row){
for(long col = 0; col < nCols; col += nCols2Skip){
triplets.push_back(Eigen::Triplet<double, long>(row, col, 1));
}
}
std::cout << "filling mat" << std::endl << std::flush;
mat.setFromTriplets(triplets.begin(), triplets.end());
std::cout << "Finished! nnz " << mat.nonZeros() << std::endl;
//Stupid way to check memory consumption
std::cin.get();
在我的例子中,这个例子消耗了大约26 Gb的峰值(在“填充垫”和“完成”之间)和18 Gb。(我通过htop
进行了所有检查)。~ 8 GB的开销对我来说相当大(在我的“真实的世界”任务中我有更大的开销)。
所以我有两个问题:
1.如何用尽可能少的开销填充Eigen::SparseMatrix
的稀疏模式?
1.为什么setFromTriplets
需要这么多内存?
如果我的例子是错的,请告诉我。
我的Eigen版本是3.3.2
PS对不起我的英语
编辑:看起来手动插入(使用预分配)每个三元组的工作速度更快,峰值时需要的内存更少。但我还是想知道是否可以手动设置稀疏模式。
1条答案
按热度按时间ljsrvy3e1#
广告1:如果你能保证按字典顺序插入元素,你甚至可以通过使用内部函数
startVec
和insertBack
比普通的insert
更高效。Ad 2:如果你使用
setFromTriplets
,你需要大约是最终矩阵大小的两倍(加上你的Triplet容器的大小),因为元素首先被插入到矩阵的转置版本中,然后被转置到最终矩阵中,以确保所有内部向量都被排序。如果你事先知道矩阵的结构,这显然是相当浪费内存的,但它的目的是处理任意的输入数据。在你的例子中,你有5000000 * 100000 / 1000 = 5e 8个元素。一个
Triplet
需要8+8+8 = 24个字节(对于vector
来说大约是12 Gb),稀疏矩阵的每个元素需要8+8=16个字节(一个double
用于值,一个long
用于内部索引),即每个矩阵大约8 Gb,所以总共需要大约28 Gb,大约是26 Gib。奖励:如果你的矩阵有一些特殊的结构,可以更有效地存储,并且你愿意深入挖掘Eigen内部,你也可以考虑实现一个从
Eigen::SparseBase<>
继承的新类型(但我不重新评论这个,除非内存/性能对你来说非常关键,并且你愿意阅读大量“稀疏”文档的内部Eigen代码...)。然而,在这种情况下,可能更容易考虑您打算用矩阵做什么,并尝试只实现特殊操作。