swissroll
swissroll

Reputation: 33

Eigen: sparse matrix pruned() does not remove entries below threshold

I want to use Eigen for sparse matrix multiplications, where in each iteration I want to remove all entries below a certain threshold. It seems to me that Eigen only removes elements exactly equal zero.

I am running Eigen 3.3.7, compiling with g++.

#include <Eigen/Sparse>
#include <Eigen/Dense>
#include <iostream>

using namespace Eigen;
typedef SparseMatrix<double> CscMat;            
typedef SparseMatrix<double,RowMajor> CsrMat;    

int N = 4;
CsrMat S, S2;

MatrixXd D(N, N), D2(N,N);
D << 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16;
D *= 0.1;

S = D.sparseView(0.5);
std::cout << D  << std::endl;
std::cout << S.nonZeros()  << std::endl;

D2 = D;
D2 = (D2.array() < 0.5).select(0, D2);
S2 = D2.sparseView();
std::cout << D  << std::endl;
std::cout << S2.nonZeros() << std::endl;

In the above S.nonzeros() returns 16, instead of expected 12 like in S2.nonzeros().

The output is:

0.1 0.2 0.3 0.4
0.5 0.6 0.7 0.8
0.9   1 1.1 1.2
1.3 1.4 1.5 1.6
16

  0   0   0   0
0.5 0.6 0.7 0.8
0.9   1 1.1 1.2
1.3 1.4 1.5 1.6
12

Upvotes: 3

Views: 1256

Answers (2)

Avi Ginsburg
Avi Ginsburg

Reputation: 10596

There is a second parameter to sparseView which is reference. In the end, the product of the two will determine the threshold, so you should use the line:

S = D.sparseView(0.5, 1.0 - std::numeric_limits<double>::epsilon());

to obtain what you seem to want.

The actual code that does the evaluation is in MathFunctions.h

static inline bool isMuchSmallerThan(const Scalar& x, const OtherScalar& y, 
                                     const RealScalar& prec)
{
   return numext::abs(x) <= numext::abs(y) * prec;
}

where the default prec of type double is (currently) 1e-12.

Upvotes: 2

ggael
ggael

Reputation: 29265

If you read the doc of sparseView you'll see that the first argument is not an absolute threshold but a reference non-zero (or the expected magnitude if you prefer). Then the second, optional, argument is the relative threshold. This is the same logic as with pruned(). If you want an absolute threshold, then you can either do:

S = D.sparseView(1,0.5);
S = D.sparseView(0.5,1);

Upvotes: 2

Related Questions