4

I wonder is there any good way to extract blocks/ROIs from Eigen::SparseMatrix? More precisely, what I want to extract is inner vectors.

What I want to do is like:

typedef Eigen::SparseMatrix<double,Eigen::RowMajor> SpMat;
// Prepare some sparse matrix
SpMat spmat;
// Extract lines from it
const SpMat& row_i = spmat.innerVector(i);
const SpMat& row_j = spmat.innerVector(j);
// Some calculation with row_i and row_j...

As I tested, the data of row_i and row_j is copied (!!) from spmat. However, obviously, it is inefficient. The data (esp. row_i.m_data.m_values & row_i.m_data.m_indices) of inner vectors is continuous part of original data (spmat.m_data.m_values & spmat.m_data.m_indices resp.), so there should be smarter way.

I may be able to implement new method to do this, but it require me a tough digging into the source code. So I don't want to.

Any help is grateful! Thanks in advance.

2 Answers2

4

You can either use the c++11 auto keyword to declare row_iand row_j as true read-write expressions, or use the proper type:

const auto row_i = spmap.innerVector(i); // C++11 version
const SpMat::InnerVectorReturnType row_i = spmap.innerVector(i); // C++98 version

Moreover, not that by default a SparseMatrix is stored in column major, therefore an "inner-vector" is a column. If you want to reference rows, then you have to use a row-major storage layout:

typedef Eigen::SparseMatrix<double,RowMajor> SpMat;
ggael
  • 28,425
  • 2
  • 65
  • 71
2

You can try to use the MappedSparseMatrix class. It wraps an existing set of data and associated parameters (I think, I've never used it). I assume it works similarly to the Eigen::Map class but I may be wrong.

MappedSparseMatrix<double> mat(int rows, int cols, int nnz,
                    int* outerIndexPtr, int* innerIndexPtr,
                    Scalar* valuePtr);

Source

Avi Ginsburg
  • 10,323
  • 3
  • 29
  • 56
  • Thanks, it also solves my problem. I can do like `Eigen::MappedSparseMatrix row_i_map(1, spmat.innerSize(), nnz, spmat.outerIndexPtr()+j, spmat.innerIndexPtr(), spmat.valuePtr()); `. For later users, I point out that `MappedSparseMatrix` expect `innerIndexPtr` and `valuePtr` to be continuous on memory. This mean, you can use only with `innerVecotr(s)` and if you want extract multiple inner vectors, original matrix should be [compressd](http://eigen.tuxfamily.org/dox/classEigen_1_1SparseMatrix.html#a4549e80dac9fd4f4c9ecee00814ecaa5). – Shinichi TAMURA Oct 29 '15 at 08:35
  • @ShinichiTAMURA is there a way to know how many items each of the outer, inner and values arrays will hold? If say we'd need to create a deep copy and `memcpy` these arrays, is there a way to extract these size? The CSR definition of nnz for values and innerIndex, and (n+1) for outerIndex does not seem to work properly. Link for CSR: http://www.netlib.org/linalg/html_templates/node91.html – Bar Aug 21 '18 at 00:26
  • @Bar You can look at [this](https://stackoverflow.com/questions/24593085/serializing-decomposed-matrix-from-eigen-sparselu-object/24595433#24595433) to see an example of serializing s sparse matrix. Look for `outS = m.outerSize();`. – Avi Ginsburg Aug 21 '18 at 04:45
  • Thanks @AviGinsburg. One more question: Is the creation of a MappedSparseMatrix zero-copy, or does it involve data copying? – Bar Aug 21 '18 at 18:20
  • @Bar zero copy. – Avi Ginsburg Aug 22 '18 at 02:54