histogram_sort.hpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293
  1. // Copyright 2009 The Trustees of Indiana University.
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // Authors: Jeremiah Willcock
  6. // Andrew Lumsdaine
  7. #ifndef BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP
  8. #define BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP
  9. #include <boost/assert.hpp>
  10. namespace boost {
  11. namespace graph {
  12. namespace detail {
  13. template<typename InputIterator>
  14. size_t
  15. reserve_count_for_single_pass_helper(InputIterator, InputIterator,
  16. std::input_iterator_tag)
  17. {
  18. // Do nothing: we have no idea how much storage to reserve.
  19. return 0;
  20. }
  21. template<typename InputIterator>
  22. size_t
  23. reserve_count_for_single_pass_helper(InputIterator first, InputIterator last,
  24. std::random_access_iterator_tag)
  25. {
  26. using std::distance;
  27. typename std::iterator_traits<InputIterator>::difference_type n =
  28. distance(first, last);
  29. return (size_t)n;
  30. }
  31. template<typename InputIterator>
  32. size_t
  33. reserve_count_for_single_pass(InputIterator first, InputIterator last) {
  34. typedef typename std::iterator_traits<InputIterator>::iterator_category
  35. category;
  36. return reserve_count_for_single_pass_helper(first, last, category());
  37. }
  38. template <typename KeyIterator, typename RowstartIterator,
  39. typename VerticesSize, typename KeyFilter, typename KeyTransform>
  40. void
  41. count_starts
  42. (KeyIterator begin, KeyIterator end,
  43. RowstartIterator starts, // Must support numverts + 1 elements
  44. VerticesSize numkeys,
  45. KeyFilter key_filter,
  46. KeyTransform key_transform) {
  47. typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
  48. // Put the degree of each vertex v into m_rowstart[v + 1]
  49. for (KeyIterator i = begin; i != end; ++i) {
  50. if (key_filter(*i)) {
  51. BOOST_ASSERT (key_transform(*i) < numkeys);
  52. ++starts[key_transform(*i) + 1];
  53. }
  54. }
  55. // Compute the partial sum of the degrees to get the actual values of
  56. // m_rowstart
  57. EdgeIndex start_of_this_row = 0;
  58. starts[0] = start_of_this_row;
  59. for (VerticesSize i = 1; i < numkeys + 1; ++i) {
  60. start_of_this_row += starts[i];
  61. starts[i] = start_of_this_row;
  62. }
  63. }
  64. template <typename KeyIterator, typename RowstartIterator,
  65. typename NumKeys,
  66. typename Value1InputIter,
  67. typename Value1OutputIter, typename KeyFilter, typename KeyTransform>
  68. void
  69. histogram_sort(KeyIterator key_begin, KeyIterator key_end,
  70. RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
  71. NumKeys numkeys,
  72. Value1InputIter values1_begin,
  73. Value1OutputIter values1_out,
  74. KeyFilter key_filter,
  75. KeyTransform key_transform) {
  76. typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
  77. // Histogram sort the edges by their source vertices, putting the targets
  78. // into m_column. The index current_insert_positions[v] contains the next
  79. // location to insert out edges for vertex v.
  80. std::vector<EdgeIndex>
  81. current_insert_positions(rowstart, rowstart + numkeys);
  82. Value1InputIter v1i = values1_begin;
  83. for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i) {
  84. if (key_filter(*i)) {
  85. NumKeys source = key_transform(*i);
  86. BOOST_ASSERT (source < numkeys);
  87. EdgeIndex insert_pos = current_insert_positions[source];
  88. ++current_insert_positions[source];
  89. values1_out[insert_pos] = *v1i;
  90. }
  91. }
  92. }
  93. template <typename KeyIterator, typename RowstartIterator,
  94. typename NumKeys,
  95. typename Value1InputIter,
  96. typename Value1OutputIter,
  97. typename Value2InputIter,
  98. typename Value2OutputIter,
  99. typename KeyFilter, typename KeyTransform>
  100. void
  101. histogram_sort(KeyIterator key_begin, KeyIterator key_end,
  102. RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
  103. NumKeys numkeys,
  104. Value1InputIter values1_begin,
  105. Value1OutputIter values1_out,
  106. Value2InputIter values2_begin,
  107. Value2OutputIter values2_out,
  108. KeyFilter key_filter,
  109. KeyTransform key_transform) {
  110. typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
  111. // Histogram sort the edges by their source vertices, putting the targets
  112. // into m_column. The index current_insert_positions[v] contains the next
  113. // location to insert out edges for vertex v.
  114. std::vector<EdgeIndex>
  115. current_insert_positions(rowstart, rowstart + numkeys);
  116. Value1InputIter v1i = values1_begin;
  117. Value2InputIter v2i = values2_begin;
  118. for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i, ++v2i) {
  119. if (key_filter(*i)) {
  120. NumKeys source = key_transform(*i);
  121. BOOST_ASSERT (source < numkeys);
  122. EdgeIndex insert_pos = current_insert_positions[source];
  123. ++current_insert_positions[source];
  124. values1_out[insert_pos] = *v1i;
  125. values2_out[insert_pos] = *v2i;
  126. }
  127. }
  128. }
  129. template <typename KeyIterator, typename RowstartIterator,
  130. typename NumKeys,
  131. typename Value1Iter,
  132. typename KeyTransform>
  133. void
  134. histogram_sort_inplace(KeyIterator key_begin,
  135. RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
  136. NumKeys numkeys,
  137. Value1Iter values1,
  138. KeyTransform key_transform) {
  139. typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
  140. // 1. Copy m_rowstart (except last element) to get insert positions
  141. std::vector<EdgeIndex> insert_positions(rowstart, rowstart + numkeys);
  142. // 2. Swap the sources and targets into place
  143. for (size_t i = 0; i < rowstart[numkeys]; ++i) {
  144. BOOST_ASSERT (key_transform(key_begin[i]) < numkeys);
  145. // While edge i is not in the right bucket:
  146. while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) {
  147. // Add a slot in the right bucket
  148. size_t target_pos = insert_positions[key_transform(key_begin[i])]++;
  149. BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]);
  150. if (target_pos == i) continue;
  151. // Swap this edge into place
  152. using std::swap;
  153. swap(key_begin[i], key_begin[target_pos]);
  154. swap(values1[i], values1[target_pos]);
  155. }
  156. }
  157. }
  158. template <typename KeyIterator, typename RowstartIterator,
  159. typename NumKeys,
  160. typename Value1Iter,
  161. typename Value2Iter,
  162. typename KeyTransform>
  163. void
  164. histogram_sort_inplace(KeyIterator key_begin,
  165. RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
  166. NumKeys numkeys,
  167. Value1Iter values1,
  168. Value2Iter values2,
  169. KeyTransform key_transform) {
  170. typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
  171. // 1. Copy m_rowstart (except last element) to get insert positions
  172. std::vector<EdgeIndex> insert_positions(rowstart, rowstart + numkeys);
  173. // 2. Swap the sources and targets into place
  174. for (size_t i = 0; i < rowstart[numkeys]; ++i) {
  175. BOOST_ASSERT (key_transform(key_begin[i]) < numkeys);
  176. // While edge i is not in the right bucket:
  177. while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) {
  178. // Add a slot in the right bucket
  179. size_t target_pos = insert_positions[key_transform(key_begin[i])]++;
  180. BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]);
  181. if (target_pos == i) continue;
  182. // Swap this edge into place
  183. using std::swap;
  184. swap(key_begin[i], key_begin[target_pos]);
  185. swap(values1[i], values1[target_pos]);
  186. swap(values2[i], values2[target_pos]);
  187. }
  188. }
  189. }
  190. template <typename InputIterator, typename VerticesSize>
  191. void split_into_separate_coords(InputIterator begin, InputIterator end,
  192. std::vector<VerticesSize>& firsts,
  193. std::vector<VerticesSize>& seconds) {
  194. firsts.clear();
  195. seconds.clear();
  196. size_t reserve_size
  197. = detail::reserve_count_for_single_pass(begin, end);
  198. firsts.reserve(reserve_size);
  199. seconds.reserve(reserve_size);
  200. for (; begin != end; ++begin) {
  201. std::pair<VerticesSize, VerticesSize> edge = *begin;
  202. firsts.push_back(edge.first);
  203. seconds.push_back(edge.second);
  204. }
  205. }
  206. template <typename InputIterator, typename VerticesSize, typename SourceFilter>
  207. void split_into_separate_coords_filtered
  208. (InputIterator begin, InputIterator end,
  209. std::vector<VerticesSize>& firsts,
  210. std::vector<VerticesSize>& seconds,
  211. const SourceFilter& filter) {
  212. firsts.clear();
  213. seconds.clear();
  214. for (; begin != end; ++begin) {
  215. std::pair<VerticesSize, VerticesSize> edge = *begin;
  216. if (filter(edge.first)) {
  217. firsts.push_back(edge.first);
  218. seconds.push_back(edge.second);
  219. }
  220. }
  221. }
  222. template <typename InputIterator, typename PropInputIterator,
  223. typename VerticesSize, typename PropType, typename SourceFilter>
  224. void split_into_separate_coords_filtered
  225. (InputIterator begin, InputIterator end,
  226. PropInputIterator props,
  227. std::vector<VerticesSize>& firsts,
  228. std::vector<VerticesSize>& seconds,
  229. std::vector<PropType>& props_out,
  230. const SourceFilter& filter) {
  231. firsts.clear();
  232. seconds.clear();
  233. props_out.clear();
  234. for (; begin != end; ++begin) {
  235. std::pair<VerticesSize, VerticesSize> edge = *begin;
  236. if (filter(edge.first)) {
  237. firsts.push_back(edge.first);
  238. seconds.push_back(edge.second);
  239. props_out.push_back(*props);
  240. }
  241. ++props;
  242. }
  243. }
  244. // The versions of operator()() here can't return by reference because the
  245. // actual type passed in may not match Pair, in which case the reference
  246. // parameter is bound to a temporary that could end up dangling after the
  247. // operator returns.
  248. template <typename Pair>
  249. struct project1st {
  250. typedef typename Pair::first_type result_type;
  251. result_type operator()(const Pair& p) const {return p.first;}
  252. };
  253. template <typename Pair>
  254. struct project2nd {
  255. typedef typename Pair::second_type result_type;
  256. result_type operator()(const Pair& p) const {return p.second;}
  257. };
  258. }
  259. }
  260. }
  261. #endif // BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP