1 // Copyright 2009 The Trustees of Indiana University.
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
7 // Authors: Jeremiah Willcock
10 #ifndef BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP
11 #define BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP
13 #include <boost/assert.hpp>
19 template<typename InputIterator>
21 reserve_count_for_single_pass_helper(InputIterator, InputIterator,
22 std::input_iterator_tag)
24 // Do nothing: we have no idea how much storage to reserve.
28 template<typename InputIterator>
30 reserve_count_for_single_pass_helper(InputIterator first, InputIterator last,
31 std::random_access_iterator_tag)
34 typename std::iterator_traits<InputIterator>::difference_type n =
35 distance(first, last);
39 template<typename InputIterator>
41 reserve_count_for_single_pass(InputIterator first, InputIterator last) {
42 typedef typename std::iterator_traits<InputIterator>::iterator_category
44 return reserve_count_for_single_pass_helper(first, last, category());
47 template <typename KeyIterator, typename RowstartIterator,
48 typename VerticesSize, typename KeyFilter, typename KeyTransform>
51 (KeyIterator begin, KeyIterator end,
52 RowstartIterator starts, // Must support numverts + 1 elements
55 KeyTransform key_transform) {
57 typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
59 // Put the degree of each vertex v into m_rowstart[v + 1]
60 for (KeyIterator i = begin; i != end; ++i) {
62 BOOST_ASSERT (key_transform(*i) < numkeys);
63 ++starts[key_transform(*i) + 1];
67 // Compute the partial sum of the degrees to get the actual values of
69 EdgeIndex start_of_this_row = 0;
70 starts[0] = start_of_this_row;
71 for (VerticesSize i = 1; i < numkeys + 1; ++i) {
72 start_of_this_row += starts[i];
73 starts[i] = start_of_this_row;
77 template <typename KeyIterator, typename RowstartIterator,
79 typename Value1InputIter,
80 typename Value1OutputIter, typename KeyFilter, typename KeyTransform>
82 histogram_sort(KeyIterator key_begin, KeyIterator key_end,
83 RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
85 Value1InputIter values1_begin,
86 Value1OutputIter values1_out,
88 KeyTransform key_transform) {
90 typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
92 // Histogram sort the edges by their source vertices, putting the targets
93 // into m_column. The index current_insert_positions[v] contains the next
94 // location to insert out edges for vertex v.
95 std::vector<EdgeIndex>
96 current_insert_positions(rowstart, rowstart + numkeys);
97 Value1InputIter v1i = values1_begin;
98 for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i) {
100 NumKeys source = key_transform(*i);
101 BOOST_ASSERT (source < numkeys);
102 EdgeIndex insert_pos = current_insert_positions[source];
103 ++current_insert_positions[source];
104 values1_out[insert_pos] = *v1i;
109 template <typename KeyIterator, typename RowstartIterator,
111 typename Value1InputIter,
112 typename Value1OutputIter,
113 typename Value2InputIter,
114 typename Value2OutputIter,
115 typename KeyFilter, typename KeyTransform>
117 histogram_sort(KeyIterator key_begin, KeyIterator key_end,
118 RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
120 Value1InputIter values1_begin,
121 Value1OutputIter values1_out,
122 Value2InputIter values2_begin,
123 Value2OutputIter values2_out,
124 KeyFilter key_filter,
125 KeyTransform key_transform) {
127 typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
129 // Histogram sort the edges by their source vertices, putting the targets
130 // into m_column. The index current_insert_positions[v] contains the next
131 // location to insert out edges for vertex v.
132 std::vector<EdgeIndex>
133 current_insert_positions(rowstart, rowstart + numkeys);
134 Value1InputIter v1i = values1_begin;
135 Value2InputIter v2i = values2_begin;
136 for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i, ++v2i) {
137 if (key_filter(*i)) {
138 NumKeys source = key_transform(*i);
139 BOOST_ASSERT (source < numkeys);
140 EdgeIndex insert_pos = current_insert_positions[source];
141 ++current_insert_positions[source];
142 values1_out[insert_pos] = *v1i;
143 values2_out[insert_pos] = *v2i;
148 template <typename KeyIterator, typename RowstartIterator,
151 typename KeyTransform>
153 histogram_sort_inplace(KeyIterator key_begin,
154 RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
157 KeyTransform key_transform) {
159 typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
161 // 1. Copy m_rowstart (except last element) to get insert positions
162 std::vector<EdgeIndex> insert_positions(rowstart, rowstart + numkeys);
163 // 2. Swap the sources and targets into place
164 for (size_t i = 0; i < rowstart[numkeys]; ++i) {
165 BOOST_ASSERT (key_transform(key_begin[i]) < numkeys);
166 // While edge i is not in the right bucket:
167 while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) {
168 // Add a slot in the right bucket
169 size_t target_pos = insert_positions[key_transform(key_begin[i])]++;
170 BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]);
171 if (target_pos == i) continue;
172 // Swap this edge into place
174 swap(key_begin[i], key_begin[target_pos]);
175 swap(values1[i], values1[target_pos]);
180 template <typename KeyIterator, typename RowstartIterator,
184 typename KeyTransform>
186 histogram_sort_inplace(KeyIterator key_begin,
187 RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed
191 KeyTransform key_transform) {
193 typedef typename std::iterator_traits<RowstartIterator>::value_type EdgeIndex;
195 // 1. Copy m_rowstart (except last element) to get insert positions
196 std::vector<EdgeIndex> insert_positions(rowstart, rowstart + numkeys);
197 // 2. Swap the sources and targets into place
198 for (size_t i = 0; i < rowstart[numkeys]; ++i) {
199 BOOST_ASSERT (key_transform(key_begin[i]) < numkeys);
200 // While edge i is not in the right bucket:
201 while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) {
202 // Add a slot in the right bucket
203 size_t target_pos = insert_positions[key_transform(key_begin[i])]++;
204 BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]);
205 if (target_pos == i) continue;
206 // Swap this edge into place
208 swap(key_begin[i], key_begin[target_pos]);
209 swap(values1[i], values1[target_pos]);
210 swap(values2[i], values2[target_pos]);
215 template <typename InputIterator, typename VerticesSize>
216 void split_into_separate_coords(InputIterator begin, InputIterator end,
217 std::vector<VerticesSize>& firsts,
218 std::vector<VerticesSize>& seconds) {
222 = detail::reserve_count_for_single_pass(begin, end);
223 firsts.reserve(reserve_size);
224 seconds.reserve(reserve_size);
225 for (; begin != end; ++begin) {
226 std::pair<VerticesSize, VerticesSize> edge = *begin;
227 firsts.push_back(edge.first);
228 seconds.push_back(edge.second);
232 template <typename InputIterator, typename VerticesSize, typename SourceFilter>
233 void split_into_separate_coords_filtered
234 (InputIterator begin, InputIterator end,
235 std::vector<VerticesSize>& firsts,
236 std::vector<VerticesSize>& seconds,
237 const SourceFilter& filter) {
240 for (; begin != end; ++begin) {
241 std::pair<VerticesSize, VerticesSize> edge = *begin;
242 if (filter(edge.first)) {
243 firsts.push_back(edge.first);
244 seconds.push_back(edge.second);
249 template <typename InputIterator, typename PropInputIterator,
250 typename VerticesSize, typename PropType, typename SourceFilter>
251 void split_into_separate_coords_filtered
252 (InputIterator begin, InputIterator end,
253 PropInputIterator props,
254 std::vector<VerticesSize>& firsts,
255 std::vector<VerticesSize>& seconds,
256 std::vector<PropType>& props_out,
257 const SourceFilter& filter) {
261 for (; begin != end; ++begin) {
262 std::pair<VerticesSize, VerticesSize> edge = *begin;
263 if (filter(edge.first)) {
264 firsts.push_back(edge.first);
265 seconds.push_back(edge.second);
266 props_out.push_back(*props);
272 // The versions of operator()() here can't return by reference because the
273 // actual type passed in may not match Pair, in which case the reference
274 // parameter is bound to a temporary that could end up dangling after the
277 template <typename Pair>
279 typedef typename Pair::first_type result_type;
280 result_type operator()(const Pair& p) const {return p.first;}
283 template <typename Pair>
285 typedef typename Pair::second_type result_type;
286 result_type operator()(const Pair& p) const {return p.second;}
293 #endif // BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP