C++ 在没有内存开销的情况下设置Eigen::SparseMatrix的稀疏模式

C++ 在没有内存开销的情况下设置Eigen::SparseMatrix的稀疏模式,c++,memory,sparse-matrix,eigen3,C++,Memory,Sparse Matrix,Eigen3,我需要设置Eigen::SparseMatrix的稀疏模式,我已经知道了(我有唯一的排序列索引和行偏移量)。显然,通过setFromTriplets是可能的,但不幸的是,setFromTriplets需要大量额外的内存(至少在我的情况下) 我写了一个小例子 const long nRows = 5000000; const long nCols = 100000; const long nCols2Skip = 1000; //It's quite big! const long nTriple

我需要设置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();
const long nRows=5000000;
const long nCols=100000;
常数长nCols2Skip=1000;
//它相当大!
常量长nTriplets2Reserve=nRows*(nCols/nCols2Skip)*1.1;
本征::SparseMatrix mat(nRows,nCols);
std::载体三联体;
三胞胎储备(Ntriplets2储备);
用于(长行=0;行std::coutad1:如果您能保证按字典顺序插入元素,那么通过使用内部函数和,您甚至可以比普通的
insert
更高效

Ad 2:如果使用
setFromTriplets
则需要大约两倍于矩阵最终大小(加上三元组容器的大小),因为元素首先插入到矩阵的转置版本中,然后转置到最终矩阵,以确保所有内部向量都已排序。如果您事先知道矩阵的结构,这显然是相当大的内存浪费,但它用于处理任意输入数据

在您的示例中,有5000000*100000/1000=5e8个元素。一个
三元组需要8+8+8=24字节(对于
向量
),稀疏矩阵的每个元素需要8+8=16字节(一个
双元组
,一个
长元组
,对于内部索引),也就是说,每个矩阵大约需要8Gb,因此总共需要28Gb,大约是26GB

奖金: 如果你的矩阵有一些特殊的结构,它可以更有效地存储,并且你愿意深入挖掘本征内件,你也可以考虑继承一个新的类型,从<代码> EGEN::SARSEBASE (但我不建议这样做,除非内存/性能对您来说非常关键,并且您愿意阅读大量“稀疏”的内部特征码…)。但是,在这种情况下,考虑您打算对矩阵做什么可能更容易,并尝试仅为此实现特殊操作