Search code examples
c++eigeneigen3

Number of non zeros elements in Eigen sparse matrix after - binary operator not changing


SparseMatrix<int,RowMajor> sm(3,3),sm1;
sm.insert(0,0)=1;
sm.insert(1,1)=1;
sm.insert(2,2)=1;
sm.insert(1,2)=1;
sm.insert(2,1)=1;

SparseMatrix<int,RowMajor> I(3,3);
I.insert(0,0)=1;
I.insert(1,1)=1;
I.insert(2,2)=1;
cout<<"SM matrix \n"<<sm<<endl;
sm1=sm-I;
cout<<"SM1 Matrix"<<sm1<<endl;
cout<<"the number of nonzeros\n"<<sm1.nonZeros()<<endl;

Output

SM matrix 
Nonzero entries:
(1,0) (_,_) (1,1) (1,2) (1,1) (1,2) 

Outer pointers:
0 2 4  $
Inner non zeros:
1 2 2  $

1 0 0 
0 1 1 
0 1 1 

SM1 MatrixNonzero entries:
(0,0) (0,1) (1,2) (1,1) (0,2) 

Outer pointers:
0 1 3  $

0 0 0 
0 0 1 `
0 1 0 

the number of nonzeros
5

Solution

  • sm1.nonZeros() does not look at the values of the matrix, rather it returns the size of the inner array that was allocated to store values:

    /** \returns the number of non zero coefficients */
    inline Index nonZeros() const
    {
      if(m_innerNonZeros)
        return innerNonZeros().sum();
      return static_cast<Index>(m_data.size());
    }
    

    If you were to look at that array in a debugger or by accessing it via sm1.valuePtr() you would see something like this:

    sm1.m_data.m_values == {0, 0, 1, 1, 0}
    

    If it were a dense matrix, you could do something like (m1.array() != 0).count(), but that doesn't work with the sparse module. A workaround would be to use a map as follows:

    cout<<"the number of nonzeros with comparison: \n"
        << (Eigen::Map<Eigen::VectorXi> (sm1.valuePtr(), sm1.nonZeros()).array() != 0).count()
        << endl;
    

    which actually compares each value to 0 and outputs the correct answer.

    If you're sure that you won't be adding modifying the newly zeroed values, you can prune the sparse matrix:

    sm1.prune(1);
    cout<<"the number of pruned nonzeros\n"<<sm1.nonZeros()<<endl;
    

    This first removes the values below the threshold (1 in this case) and the data array looks like:

    sm1.m_data.m_values == {1, 1}