This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Problem initializing sparse matrices

Tags: None
(comma "," separated)
ssylvan
Registered Member
Posts
2
Karma
0
I'm building a big linear system that is very sparse. I'd like to build up the matrix row by row by just setting them from SparseVector:

Code: Select all
   
Eigen::SparseMatrix<float> A(numRows, numCols);   
Eigen::SparseVector<float> r(numCols);
A.row(0) = r;
// Comment the last line out, and no compiler errors.
// Leave it in and get errors about missing resize:
// eigen\src\sparsecore\sparsematrixbase.h(209): error C2039: 'resize': is not a member of 'Eigen::Block<Derived,1,-1,false>'


I also tried r.transpose (since it's a column vector...) but that didn't work either. Anyone have any ideas for how to set things row-by-row like this? The reason I'm not setting them element-wise (or with triplets) is that the rows are really the sum of two sparse vectors so I need to add two vectors together and set them as the row.
User avatar
nate-y
Registered Member
Posts
5
Karma
0
Sparse vectors and matrices store only non-zero elements and the corresponding index. When you go from a sparse vector to a sparse matrix, you are changing the way the indices are counted. For example, your vector has 100 elements and one element is (value=1.0, index=50). When you assign that to a 100x100 matrix, the value is still 1.0 but the index depends on the target matrix.

Why do you need to take a set of vectors and collect them into a matrix in the end? In my (limited) experience, sparse matrices represent either broad networks (like hyperlinks between the entire Internet) in which case values are set by hand or banded matrices in finite differences / volumes which would be unnecessarily difficult to set row by row.

But I'm not an expert on sparse matrices, so I could be off.
ssylvan
Registered Member
Posts
2
Karma
0
Yes, I understand how the storage works, I would still expect assignment to work (it would just copy the elements to the matrix so that the indices work out for the matrix).

The reason I need this is that I'm building up a pretty large linear system (tens of thousands of variables, hundreds of thousands of equations), for each row I need to produce an equation and it just so happens that it's easier to do so in pieces (corresponding to the logical components of the variables) and add them all up. Specifically, each row in the matrix represent an equation like x_245 + x_2411 - x_3252 - x_5213 = 0. So there's only a few non-zero elements per row, but the way they correspond to domain data means that e.g. the first two come from one logical concept and the second two come from another logical concept - that said each variable (column) may appear multiple times. Now of course I can just loop through my variables and set them individually (adding or subtracting from the existing matrix element) but it just seems silly that I have to do that manually when Eigen already has a concept of sparse vectors.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
At the moment, for your use case, the fastest way would be to use a row-major matrix for the assembly, reserve memory first, and then insert the row vectors manually, like:
Code: Select all
  SparseMatrix<float,RowMajor> mat(nb_rows,nb_cols);
  mat.reserve(VectorXi::Constant(nb_rows, max_nnz_per_rows)); // Eigen 3.2
  mat.reserve(b_rows * average_nnz_per_rows); // Eigen 3.3
  for(each row i)
    for(SparseVector<float>::InnerIterator it(row_i); it; ++it)
      mat.insert(i,it.index()) = it.value();
tienhung
Registered Member
Posts
29
Karma
0
ggael wrote:At the moment, for your use case, the fastest way would be to use a row-major matrix for the assembly, reserve memory first, and then insert the row vectors manually, like:
Code: Select all
  SparseMatrix<float,RowMajor> mat(nb_rows,nb_cols);
  mat.reserve(VectorXi::Constant(nb_rows, max_nnz_per_rows)); // Eigen 3.2
  mat.reserve(b_rows * average_nnz_per_rows); // Eigen 3.3
  for(each row i)
    for(SparseVector<float>::InnerIterator it(row_i); it; ++it)
      mat.insert(i,it.index()) = it.value();


Dear ggael,
So in Eigen 3.3, we just need to reserve the total number of nz values instead of reserving vector? Is there any difference in performance of these reserving ways for very large sparse matrices? Sometime estimation of nnz per column could be expensive.
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
Update

In Eigen 3.3 (devel branch), filling the vector row by row is now fine, and even faster than manually calling insert:
Code: Select all
SparseMatrix<float,RowMajor> mat(nb_rows,nb_cols);
mat.reserve(VectorXi::Constant(nb_rows, max_nnz_per_rows));
for(each row i)
  mat.row(i) = row_i;
User avatar
ggael
Moderator
Posts
3447
Karma
19
OS
tienhung wrote:So in Eigen 3.3, we just need to reserve the total number of nz values instead of reserving vector? Is there any difference in performance of these reserving ways for very large sparse matrices? Sometime estimation of nnz per column could be expensive.


That really depends on the insertion pattern... if the entries are already sorted, then yes, otherwise it is better to allocate room for each individual row or column.


Bookmarks



Who is online

Registered users: Bing [Bot], Google [Bot], q.ignora, watchstar