How to convert an Eigen sparse matrix into an array in C++ using the?

0

I have created a sparse matrix mat in C++ using the Eigen package. The matrix works fine, but I am trying to convert it into an array to use as a bitmap. The size of mat is N+1.

Naively, I tried doing the following:

  double zmat[N+1][N+1];

  for(int i=0; i<=N; i++){
      for(int j=0; j<=N; j++){
          zmat[i][j]=mat.coeffRef(i,j);
          }
  }

But this is gives me an exception when I debug:

Unhandled exception at 0x0116B2C7 in Open_GL_test.exe: 0xC00000FD: Stack overflow (parameters: 0x00000000, 0x001D2000).

Any thoughts?

c++
eigen
asked on Stack Overflow Jul 2, 2015 by Kieran Cooney • edited Aug 6, 2019 by double-beep

2 Answers

3
double zmat[N+1][N+1];

This is what is causing you trouble. Declaring a large matrix as a local variable in a function is not a good idea. Local variables are allocated on the stack. Many machines limit the size of the stack to a smallish amount of data. On my machine, the stack limit is about 8 megabytes. That means a value of N larger than about a thousand will immediately result in stack overflow. A value of N larger than several hundred (but smaller than a thousand) will result in a hard-to-trace stack overflow somewhere further down the call tree.

Don't allocate large amounts of data on the stack. Some alternatives are to

  • Declare the variable at namespace scope,
  • Allocate (and later free) the matrix using new and delete,
  • Use an ordinary Eigen matrix, which does the new and delete for you.
answered on Stack Overflow Jul 2, 2015 by David Hammen
1

David Hammen's answer is the correct one (double zmat[N+1][N+1]; is too large for the stack). However, I feel the need to throw in my two cents regarding your usage.

The double loop is unnecessarily verbose and slow. Even worse, using coeffref on each element of the matrix is actually making the matrix effectively dense. In the documentation for coeffRef it says:

If the element does not exist then it is inserted via the insert(Index,Index) function which itself turns the matrix into a non compressed form if that was not the case.
This is a O(log(nnz_j)) operation (binary search) plus the cost of insert(Index,Index) function if the element does not already exist.

This means that not only is it verbose, it's going to add to your memory requirements and may become a bottleneck. You can instead use

MatrixXd::Map(&zmat[0], (N+1), (N+1)) = mat.toDense();

or

MatrixXd::Map(zmat, (N+1), (N+1)) = mat.toDense();  // double zmat = new ...

This is not only more readable, but much more efficient as well.

answered on Stack Overflow Jul 2, 2015 by Avi Ginsburg • edited May 23, 2017 by Community

User contributions licensed under CC BY-SA 3.0