rank.hpp 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // (C) Copyright Matt Borland 2022
  2. // Use, modification and distribution are subject to the
  3. // Boost Software License, Version 1.0. (See accompanying file
  4. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_MATH_STATISTICS_DETAIL_RANK_HPP
  6. #define BOOST_MATH_STATISTICS_DETAIL_RANK_HPP
  7. #include <cstdint>
  8. #include <vector>
  9. #include <numeric>
  10. #include <utility>
  11. #include <iterator>
  12. #include <algorithm>
  13. #include <boost/math/tools/config.hpp>
  14. #ifdef BOOST_MATH_EXEC_COMPATIBLE
  15. #include <execution>
  16. #endif
  17. namespace boost { namespace math { namespace statistics { namespace detail {
  18. struct pair_equal
  19. {
  20. template <typename T1, typename T2>
  21. bool operator()(const std::pair<T1, T2>& a, const std::pair<T1, T2>& b) const
  22. {
  23. return a.first == b.first;
  24. }
  25. };
  26. }}}} // Namespaces
  27. #ifndef BOOST_MATH_EXEC_COMPATIBLE
  28. namespace boost { namespace math { namespace statistics { namespace detail {
  29. template <typename ForwardIterator, typename T = typename std::iterator_traits<ForwardIterator>::value_type>
  30. auto rank(ForwardIterator first, ForwardIterator last) -> std::vector<std::size_t>
  31. {
  32. std::size_t elements = std::distance(first, last);
  33. std::vector<std::pair<T, std::size_t>> rank_vector(elements);
  34. std::size_t i = 0;
  35. while (first != last)
  36. {
  37. rank_vector[i] = std::make_pair(*first, i);
  38. ++i;
  39. ++first;
  40. }
  41. std::sort(rank_vector.begin(), rank_vector.end());
  42. // Remove duplicates
  43. rank_vector.erase(std::unique(rank_vector.begin(), rank_vector.end(), pair_equal()), rank_vector.end());
  44. elements = rank_vector.size();
  45. std::pair<T, std::size_t> rank;
  46. std::vector<std::size_t> result(elements);
  47. for (i = 0; i < elements; ++i)
  48. {
  49. if (rank_vector[i].first != rank.first)
  50. {
  51. rank = std::make_pair(rank_vector[i].first, i);
  52. }
  53. result[rank_vector[i].second] = rank.second;
  54. }
  55. return result;
  56. }
  57. template <typename Container>
  58. inline auto rank(const Container& c) -> std::vector<std::size_t>
  59. {
  60. return rank(std::begin(c), std::end(c));
  61. }
  62. }}}} // Namespaces
  63. #else
  64. namespace boost::math::statistics::detail {
  65. template <typename ExecutionPolicy, typename ForwardIterator, typename T = typename std::iterator_traits<ForwardIterator>::value_type>
  66. auto rank(ExecutionPolicy&& exec, ForwardIterator first, ForwardIterator last)
  67. {
  68. std::size_t elements = std::distance(first, last);
  69. std::vector<std::pair<T, std::size_t>> rank_vector(elements);
  70. std::size_t i = 0;
  71. while (first != last)
  72. {
  73. rank_vector[i] = std::make_pair(*first, i);
  74. ++i;
  75. ++first;
  76. }
  77. std::sort(exec, rank_vector.begin(), rank_vector.end());
  78. // Remove duplicates
  79. rank_vector.erase(std::unique(exec, rank_vector.begin(), rank_vector.end(), pair_equal()), rank_vector.end());
  80. elements = rank_vector.size();
  81. std::pair<T, std::size_t> rank;
  82. std::vector<std::size_t> result(elements);
  83. for (i = 0; i < elements; ++i)
  84. {
  85. if (rank_vector[i].first != rank.first)
  86. {
  87. rank = std::make_pair(rank_vector[i].first, i);
  88. }
  89. result[rank_vector[i].second] = rank.second;
  90. }
  91. return result;
  92. }
  93. template <typename ExecutionPolicy, typename Container>
  94. inline auto rank(ExecutionPolicy&& exec, const Container& c)
  95. {
  96. return rank(exec, std::cbegin(c), std::cend(c));
  97. }
  98. template <typename ForwardIterator, typename T = typename std::iterator_traits<ForwardIterator>::value_type>
  99. inline auto rank(ForwardIterator first, ForwardIterator last)
  100. {
  101. return rank(std::execution::seq, first, last);
  102. }
  103. template <typename Container>
  104. inline auto rank(const Container& c)
  105. {
  106. return rank(std::execution::seq, std::cbegin(c), std::cend(c));
  107. }
  108. } // Namespaces
  109. #endif // BOOST_MATH_EXEC_COMPATIBLE
  110. #endif // BOOST_MATH_STATISTICS_DETAIL_RANK_HPP