sort eigen vectorXf in ascending order
Asked Answered
G

3

14

I'm trying to sort an Eigen VectorXf x in ascending order.

This sorts it in descending order:

std::sort(x.data(),x.data()+x.size());

and this doesn't work:

bool myfunction (int i,int j) { return (i<j); }
std::sort(x.data(),x.data()+x.size(),myfunction);

any ideas?

Gorizia answered 17/2, 2014 at 17:17 Comment(3)
Try lambda? ;-) x.data()+x.size(), [](int a, int b){return a > b})... Or just send in std::greater<int>(). Or reverse after sorting. Or...Resemble
Okay, I'll write it up as an answer so it can be answered.Resemble
Your original method sort it as ascending order actually.Illjudged
R
9

Preface
Since the original question turned out to be a misunderstanding, and the code in it is already the proper answer, I decided to write up and post a bit about using std::sort in general.

std::sort sorts range in ascending order defined by weak ordering of the elements. By default it uses < operator defined on elements, but it can also take a function object or functor to provide the comparison. This functor needs to have properly overloaded function with signature of bool operator()(const T& lhs, const T& rhs) const. An example of this follows:

struct FooSorter {
    bool operator (const Foo& lhs, const Foo& rhs) const {
        return lhs.ham_index < rhs.ham_index;
    }
};
/* ... */
std::sort(begin(vec), end(vec), FooSorter());

This would sort the full range represented by vec, according to criteria defined in FooSorter's operator().

Because writing custom functors for the simple things (sort in descending order, sort in ascending order) would quickly grow painful, STL provides many templated functors ready to use in functional header. The one relevant for sorting are:

  • std::equal_to implementing x == y

  • std::not_equal_to implementing x != y

  • std::greater implementing x > y

  • std::less implementing x < y

  • std::greater_equal implementing x >= y

  • std::less_equal implementing x <= y

All of these are templated and can be used for any type, that implements needed operators. Using these is easy:

std::sort(begin(vec), end(vec), std::greater<int>());

This would sort the range represented by vector in descending order.

But, since one of the biggest problems of STL algorithms was the pain of defining functors, C++11 brings a new trick: lambda functions. This lets you declare function object equivalent inline. Example follows:

std::sort(begin(vec), end(vec), [](int lhs, int rhs){return rhs > lhs});

This would also sort the range represented by vector in descending order, but we didn't have to explicitly declare a functor (or use already declared one). (This gets much better when implementing much more complex comparisons, or functors for different STL algorithms.)

Resemble answered 17/2, 2014 at 17:45 Comment(6)
@Gorizia And what error are you getting? What type are the members inside vector? Give me more information.Resemble
actually the correct answer is just std::sort(x.data(),x.data()+x.size()). I knew this before but hadn't used cpp in a while and forgot. It came back in the train. Anyway, if you change your answer, I'll be happy to accept.Gorizia
@Gorizia Aaaaaand this why one needs to read the questions carefully. :-D (Since you wrote that the usual invocation sorts your vector the wrong way round, I just wrote an answer as to how you can sort them the other way around, instead of how to sort them ascendingly.) I'll update the answer in a bit to elaborate more on std::sort, functors and such, to provide some value.Resemble
@Gorizia Okay, now it should be a bit better ;-)Resemble
thank you very much! Sorry for the original misunderstanding~but you managed to turn things around and made the internet a better place for it!Gorizia
@Gorizia std::sort(x.data(), x.data() + x.size()) breaks if the stride of the vector is not 1 i.e. non-consecutive.Rouleau
L
1

If someone is looking for an answer, here how I did it. In this way, you can get eigenvalues and corresponding eigenvectors as well. Here covariance_matrix is the matrix in which eigenvalues and eigenvectors are to be solved.

    std::vector<std::tuple<float, Eigen::VectorXf>> eigen_vectors_and_values; 

    Eigen::SelfAdjointEigenSolver<Eigen::MatrixXf> eigensolver(covariance_matrix);
    if (eigensolver.info() != Eigen::Success) {
        return;
    }
    Eigen::VectorXf eigen_values = eigensolver.eigenvalues();
    Eigen::MatrixXf eigen_vectors = eigensolver.eigenvectors();
    for(int i=0; i<eigen_values.size(); i++){
        std::tuple<float, Eigen::VectorXf> vec_and_val(eigen_values[i], eigen_vectors.row(i));
        eigen_vectors_and_values.push_back(vec_and_val);
    }
    std::sort(eigen_vectors_and_values.begin(), eigen_vectors_and_values.end(), 
        [&](const std::tuple<float, Eigen::VectorXf>& a, const std::tuple<float, Eigen::VectorXf>& b) -> bool{ 
            return std::get<0>(a) < std::get<0>(b); 
    });

Note: Be careful when selecting which eigensolver is to be used. You may find here which one to be used: https://eigen.tuxfamily.org/dox/group__Eigenvalues__Module.html

Landa answered 24/5, 2019 at 22:11 Comment(2)
Thanks, but it the first time I found an answer of another question ( #2687048) on a different page. Should you delete and move your answer to the other page ?Charlettecharley
also it should be eigen_vectors.col(i) instead of eigen_vectors.row(i) because eigen vectors are returned in a vector column.Charlettecharley
U
0

Thanks for this complete answer for sorting both, eigenvalues and eigenvectors. Is it correct to return row() in

std::tuple<float, Eigen::VectorXf> vec_and_val(eigen_values[i], eigen_vectors.row(i));

From what is stated in the documentation of Eigen, it should be col()

Unseat answered 1/7, 2019 at 10:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.