简体   繁体   中英

The speed of filling sparse matrix in Eigen depends on number of nodes or edges?

I filled edges of two network.

One is about 4000 nodes and 80000 edges.

Another one about is 80000 nodes and 1300000 edges.

The code is written like below:

SparseMatrix<int,Eigen::RowMajor> mat(nodenumber,nodenumber); //nodenumber is 4000 or 80000
mat.reserve(VectorXi::Constant(nodenumber,50)); //preserve 50 non-nero elements
for (i,j) in edges:
    mat.insert(i,j) = 1;
    mat.insert(j,i) = 1;
}

(4000 nodes,80000 edges) is done with 1.5 sec.

(80000 nodes,1300000 edges) is done with 600 sec.

But I think the speed of filling matrix should depend on edges.

That should be 1.5*1300000/80000 for (80000 nodes,1300000 edges) network.

Am I right or wrong?

How can I improve the speed of filling the matrix?

Thanks!

See this line: mat.reserve(VectorXi::Constant(nodenumber,50)); and this point of the documentation of Eigen on sparse matrix :

Note that when calling reserve(), it is not required that nnz is the exact number of nonzero elements in the final matrix. However, an exact estimation will avoid multiple reallocations during the insertion phase.

Hence, consider changing 50 by something larger than the number of edges so as to reduce repeated allocation. Nevertheless, it will only slightly reduce wall clock time, as detailed in the section Filling a sparse matrix

Because of the special storage scheme of a SparseMatrix, special care has to be taken when adding new nonzero entries. For instance, the cost of a single purely random insertion into a SparseMatrix is O(nnz), where nnz is the current number of non-zero coefficients.

As a consequence, filling the whole matrix by random insertions is O(nnz^2/2). Indeed, if you compute 80000^2 and 1300000^2, the ratio will not be too far from 1.5/600, these figures being the execution times you reported.

To gain some time, you may be interested in batch insertion , that is inserting all edges at once. Read this part of the documentation of Eigen: it really worths it! Indeed, the piece of code provided on this webpage will likely help you.

typedef Eigen::Triplet<double> T;
std::vector<T> tripletList;
tripletList.reserve(nnz);
for(...)
{
    // ...
    tripletList.push_back(T(i,j,v_ij));
}
SparseMatrixType mat(rows,cols);
mat.setFromTriplets(tripletList.begin(), tripletList.end());

As an alternative, you can also reserve storage space for each column, if you know the maximum number of non-null elements per column and if it is not too big:

mat.reserve(VectorXi::Constant(cols,6));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM