Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MATLAB find() / Numpy nonzero idioms for Eigen

Tags:

c++

matlab

eigen

Chances are this is a very stupid question but I spent a pretty absurd amount of time looking for it on the documentation, to no avail.

in MATLAB, the find() function gives me an array with the indices of nonzero elements. Numpy's np.nonzero function does something similar.

How do I do this in the C++ Eigen library? I have a Boolean array of

typedef <bool, 10, 1> foobar = MatrixA < MatrixB;

so far. Thanks!

like image 390
ejang Avatar asked Apr 27 '13 07:04

ejang


People also ask

How to find the eigenvalues and eigenvectors in NumPy?

In NumPy, there is a method for finding the eigenvalues and eigenvectors and it is linalg.eig (). The syntax of this function is below. Here “a” is the input square matrix. This function returns two values w and v. The w is the eigenvalues and v is the eigenvector. In the next section, you will learn how to find them with steps.

Is there a less than function in Eigen?

It is reasonable to expect Eigen to have a find () function. Unfortunately, Eigen doesn't have one, or even a less than operator for matrices. Fortunately, the problem isn't too difficult. Here is one solution to the problem. I am using vector to store the Column Major indices of elements > 0. You could use VectorXf if you prefer that.

How do I return the eigenvalues of a column in MATLAB?

[ ___] = eig ( ___,eigvalOption) returns the eigenvalues in the form specified by eigvalOption using any of the input or output arguments in previous syntaxes. Specify eigvalOption as 'vector' to return the eigenvalues in a column vector or as 'matrix' to return the eigenvalues in a diagonal matrix.

What is the difference between find () and find () in NumPy and MATLAB?

Linear indices are common in MATLAB programs, e.g. find () on a matrix returns them, whereas NumPy’s find behaves differently. When converting MATLAB code it might be necessary to first reshape a matrix to a linear sequence, perform some indexing operations and then reshape back.


2 Answers

Not sure if this is part of your question, but to construct the appropriate element-wise inequality result you must first cast your matrices to arrays:

MatrixXd A,B;
...
Matrix<bool,Dynamic,Dynamic> C = A.array()<B.array();

Now C is the same size as A and B and C(i,j) = A(i,j) < B(i,j).

To find all of the indices (assuming column-major order) of the true entries, you can use this compact c++11 routine---as described by libigl's conversion table:

VectorXi I = VectorXi::LinSpaced(C.size(),0,C.size()-1);
I.conservativeResize(std::stable_partition(
  I.data(), I.data()+I.size(), [&C](int i){return C(i);})-I.data());

Now I is C.nonZeros() long and contains indices of the true entries in C. These two lines essentially implement find.

like image 182
Alec Jacobson Avatar answered Sep 24 '22 21:09

Alec Jacobson


It is reasonable to expect Eigen to have a find() function. Unfortunately, Eigen doesn't have one, or even a less than operator for matrices. Fortunately, the problem isn't too difficult. Here is one solution to the problem. I am using vector to store the Column Major indices of elements > 0. You could use VectorXf if you prefer that. Use this on B - A (B-A > 0 is the same as evaluating B>A). I'm using the stl for_each() function.

#include<algorithm>
#include<vector>
#include <Eigen/Dense>
using namespace Eigen;
using namespace std;

class isGreater{
    public:
    vector<int>* GT;
    isGreater(vector<int> *g){GT = g;}
    void operator()(float i){static int it = 0; if(i>0)GT->push_back(it); it++;}
};
int main(int argc,char **argv){
    MatrixXf P = MatrixXf::Random(4,5);
    vector<int> GT;
    for_each(P.data(),P.data()+P.rows()*P.cols(),isGreater(&GT));
    cout<<P<<endl;
    for(int i=0;i<GT.size();++i)cout<<GT[i]<<" ";
    cout<<GT.size()<<endl;
    return 0;
}
like image 25
John Doe Avatar answered Sep 23 '22 21:09

John Doe