sort.h 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. #ifndef IGL_SORT_H
  2. #define IGL_SORT_H
  3. #include <vector>
  4. #include <Eigen/Core>
  5. namespace igl
  6. {
  7. // Sort the elements of a matrix X along a given dimension like matlabs sort
  8. // function
  9. //
  10. // Templates:
  11. // T should be a eigen matrix primitive type like int or double
  12. // Inputs:
  13. // X m by n matrix whose entries are to be sorted
  14. // dim dimensional along which to sort:
  15. // 1 sort each column (matlab default)
  16. // 2 sort each row
  17. // ascending sort ascending (true, matlab default) or descending (false)
  18. // Outputs:
  19. // Y m by n matrix whose entries are sorted
  20. // IX m by n matrix of indices so that if dim = 1, then in matlab notation
  21. // for j = 1:n, Y(:,j) = X(I(:,j),j); end
  22. template <typename T>
  23. inline void sort(
  24. const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
  25. const int dim,
  26. const bool ascending,
  27. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Y,
  28. Eigen::MatrixXi & IX);
  29. // Act like matlab's [Y,I] = SORT(X) for std library vectors
  30. // Templates:
  31. // T should be a class that implements the '<' comparator operator
  32. // Input:
  33. // unsorted unsorted vector
  34. // ascending sort ascending (true, matlab default) or descending (false)
  35. // Output:
  36. // sorted sorted vector, allowed to be same as unsorted
  37. // index_map an index map such that sorted[i] = unsorted[index_map[i]]
  38. template <class T>
  39. inline void sort(
  40. const std::vector<T> &unsorted,
  41. const bool ascending,
  42. std::vector<T> &sorted,
  43. std::vector<size_t> &index_map);
  44. }
  45. // Implementation
  46. #include <algorithm>
  47. #include "reorder.h"
  48. template <typename T>
  49. inline void igl::sort(
  50. const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
  51. const int dim,
  52. const bool ascending,
  53. Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & Y,
  54. Eigen::MatrixXi & IX)
  55. {
  56. // dim must be 2 or 1
  57. assert(dim == 1 || dim == 2);
  58. // Resize output
  59. Y.resize(X.rows(),X.cols());
  60. IX.resize(X.rows(),X.cols());
  61. // idea is to process each column (or row) as a std vector
  62. // get number of columns (or rows)
  63. int num_outer = (dim == 1 ? X.cols() : X.rows() );
  64. // get number of rows (or columns)
  65. int num_inner = (dim == 1 ? X.rows() : X.cols() );
  66. // loop over columns (or rows)
  67. for(int i = 0; i<num_outer;i++)
  68. {
  69. // Unsorted index map for this column (or row)
  70. std::vector<size_t> index_map(num_inner);
  71. std::vector<T> data(num_inner);
  72. for(int j = 0;j<num_inner;j++)
  73. {
  74. if(dim == 1)
  75. {
  76. data[j] = X(j,i);
  77. }else
  78. {
  79. data[j] = X(i,j);
  80. }
  81. }
  82. // sort this column (or row)
  83. sort<T>(
  84. data,
  85. ascending,
  86. data,
  87. index_map);
  88. // Copy into Y and IX
  89. for(int j = 0;j<num_inner;j++)
  90. {
  91. if(dim == 1)
  92. {
  93. Y(j,i) = data[j];
  94. IX(j,i) = index_map[j];
  95. }else
  96. {
  97. Y(i,j) = data[j];
  98. IX(i,j) = index_map[j];
  99. }
  100. }
  101. }
  102. }
  103. // Comparison struct used by sort
  104. // http://bytes.com/topic/c/answers/132045-sort-get-index
  105. template<class T> struct index_cmp
  106. {
  107. index_cmp(const T arr) : arr(arr) {}
  108. bool operator()(const size_t a, const size_t b) const
  109. {
  110. return arr[a] < arr[b];
  111. }
  112. const T arr;
  113. };
  114. template <class T>
  115. inline void igl::sort(
  116. const std::vector<T> & unsorted,
  117. const bool ascending,
  118. std::vector<T> & sorted,
  119. std::vector<size_t> & index_map)
  120. {
  121. // Original unsorted index map
  122. index_map.resize(unsorted.size());
  123. for(size_t i=0;i<unsorted.size();i++)
  124. {
  125. index_map[i] = i;
  126. }
  127. // Sort the index map, using unsorted for comparison
  128. sort(
  129. index_map.begin(),
  130. index_map.end(),
  131. index_cmp<const std::vector<T>& >(unsorted));
  132. // if not ascending then reverse
  133. if(!ascending)
  134. {
  135. std::reverse(index_map.begin(),index_map.end());
  136. }
  137. // make space for output without clobbering
  138. sorted.resize(unsorted.size());
  139. // reorder unsorted into sorted using index map
  140. igl::reorder(unsorted,index_map,sorted);
  141. }
  142. #endif