Remove zero values from Eigen Vector

Oct 31, 2019 at 9:25am
Hi,
For a program I am writing I want to obtain a Eigen::Vector with only the non zero values of another Eigen::Vector.
Lets say I have

Eigen:VectorXd myVec(9)
myVec << 1,0,3,0,0,6,8,0,9

and now I want myVecNew = 1,3,6,8,9

Is this possible without making use of a relative large piece of code with loops etc? Maybe something comparable to the nonzeros() function of Matlab

Thank you!
Oct 31, 2019 at 10:15am

1
2
vec.erase( std::remove_if (vec.begin(), vec.end(), [](int val) {return  val == 0;}),
                vec.end());


The remove_if from <algorithm> rearranges the vector and returns an iterator to the new place that you want as the new end of the vector without zero values in it, and the erase function then resizes the vector to just contain the things you wanted.

This alters the vector. If you want to retain the original, you could make a copy of it first and then work on the copy, or you could get fancy and use the copy_if function to iteratte over the original vector and only copy the values you want to the new.
Last edited on Oct 31, 2019 at 10:17am
Oct 31, 2019 at 12:23pm
Hi, thanks for your answer, but I think this method is used for std::vectors, not for Eigen..
Oct 31, 2019 at 12:26pm
1
2
std::erase( std::remove_if (vec.begin(), vec.end(), [](int val) {return  val == 0;}),
                vec.end());


std::erase does require C++20

This does assume that this Eigen::vector classs you're using provides fairly standard container support.

If it doesn't, you'll have to read the Eigen documentation to see what equivalent functions they provide.

Alternatively, if the Eigen classes don't have any support for this, do what I originally suggested, but on a vector that you created from the Eigen::vector, and turn the result back into an Eigen::vector
Last edited on Oct 31, 2019 at 12:33pm
Nov 5, 2019 at 11:36am
Unfortunately I don't think I have C++20 available.

Ill try to look in the Eigen documentation and otherwise convert it to a vector and back, but this seems like quiet some code for such a small operation..
Nov 5, 2019 at 12:25pm
If this Eigen::vector object you have is meant to be used for linear algebra operations, with this object representing a mathematical vector, then simply removing all the zeroes from one doesn't make a lot of sense and thus wouldn't be supported.
Nov 5, 2019 at 3:19pm
Yeah I guess that is true.

Ill explain the situation in more detail:
I have a matrix with zero's and some non zero values, per row I want to loop over the non zero values in that row. I want to use every non zero value in each row to as an index for something else.
For example is some languages you can do the following:
indexVector = [ 1,2,3,4,5,6,7,8,9 ]
availability = [ 0,1,0,0,1,1,0,0,0]
for index in indexVector[availability]:
etc
which will make the program loop with index = 2, index = 5, index = 6

I was looking for something equivalent, but couldn't find it so I thought of a solution where I did indexVector.cwiseproduct(availability), giving indexAvailable= [ 0,2,0,0,5,6,0,0,0 ]. After this I wanted to remove the zeros (temp =[ 2,5,6] and do a simple loop with i=0; i<temp.size(); i++ and then use temp(i) to get 2 5 and 6 as index for something else.

Now that I am typing it, it sounds rather inefficient.
It might be a completely different question, but do you have a better approach?
Nov 5, 2019 at 5:14pm
I want to use every non zero value in each row to as an index for something else

If I don’t misunderstand your question, it seems Sparse matrix manipulations is what you’re looking for:
https://eigen.tuxfamily.org/dox/group__TutorialSparse.html
(see the very first example)

Let me add your first post would be easily solved by the standard library:
Lets say I have
Eigen:VectorXd myVec(9)
myVec << 1,0,3,0,0,6,8,0,9
and now I want myVecNew = 1,3,6,8,9
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <valarray>


void print(const std::valarray<int>& what);


int main()
{
    std::valarray<int> v1 { 1, 0, 3, 0, 0, 6, 8, 0, 9 };
    std::cout << "v1:\n";
    print(v1);

    std::valarray v2 = v1[v1 != 0]; // just like that!
    std::cout << "v2:\n";
    print(v2);
}


void print(const std::valarray<int>& what)
{
    for(int i : what) {
        std::cout << i << ' ';
    }
    std::cout << '\n';
}


Output
v1:
1 0 3 0 0 6 8 0 9
v2:
1 3 6 8 9


Nov 5, 2019 at 8:01pm
indexVector = [ 1,2,3,4,5,6,7,8,9 ]
availability = [ 0,1,0,0,1,1,0,0,0]
for index in indexVector[availability]:

Like in:
1
2
3
4
5
6
for ( int dim=0; dim < N; ++dim ) {
  if ( availability[ dim ] ) {
    index = indexVector[ dim ];
    // use index
  }
}

C++20 ranges probably can hide that "if" into fancier syntax.
Nov 6, 2019 at 9:27am
@Enoizat
I will look into the sparse methods, not sure if this will help me for this specific part, but I definitely need it later on, thank you!
The second method you're mentioning works for std, not for Eigen, so I firs have to convert to a std::valarray.
This can be done by using Map from Eigen and after this it has to be converted back, how is this done?
This could definitely be a solution, but still needs the conversion.

@keskiverto
This is also a nice work around thanks!

I will look what works the best for me
Last edited on Nov 6, 2019 at 10:14am
Topic archived. No new replies allowed.