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?

user189035
  • 5,589
  • 13
  • 52
  • 112

3 Answers3

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.)

Xarn
  • 3,460
  • 1
  • 21
  • 43
  • @user189035 And what error are you getting? What type are the members inside vector? Give me more information. – Xarn Feb 17 '14 at 20:46
  • 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. – user189035 Feb 17 '14 at 20:48
  • @user189035 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. – Xarn Feb 17 '14 at 20:51
  • @user189035 Okay, now it should be a bit better ;-) – Xarn Feb 17 '14 at 21:19
  • 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! – user189035 Feb 17 '14 at 22:03
  • 1
    @user189035 `std::sort(x.data(), x.data() + x.size())` breaks if the stride of the vector is not 1 i.e. non-consecutive. – jdh8 Jul 01 '16 at 03:07
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

GPrathap
  • 7,336
  • 7
  • 65
  • 83
  • Thanks, but it the first time I found an answer of another question ( https://stackoverflow.com/questions/2686548/sorting-eigenvectors-by-their-eigenvalues-associated-sorting) on a different page. Should you delete and move your answer to the other page ? – Malick May 03 '20 at 10:52
  • also it should be `eigen_vectors.col(i)` instead of `eigen_vectors.row(i)` because eigen vectors are returned in a vector column. – Malick May 03 '20 at 11:49
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()

fguser
  • 1