// Copyright 2009 The Trustees of Indiana University. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // Authors: Jeremiah Willcock // Andrew Lumsdaine #ifndef BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP #define BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP #include namespace boost { namespace graph { namespace detail { template size_t reserve_count_for_single_pass_helper(InputIterator, InputIterator, std::input_iterator_tag) { // Do nothing: we have no idea how much storage to reserve. return 0; } template size_t reserve_count_for_single_pass_helper(InputIterator first, InputIterator last, std::random_access_iterator_tag) { using std::distance; typename std::iterator_traits::difference_type n = distance(first, last); return (size_t)n; } template size_t reserve_count_for_single_pass(InputIterator first, InputIterator last) { typedef typename std::iterator_traits::iterator_category category; return reserve_count_for_single_pass_helper(first, last, category()); } template void count_starts (KeyIterator begin, KeyIterator end, RowstartIterator starts, // Must support numverts + 1 elements VerticesSize numkeys, KeyFilter key_filter, KeyTransform key_transform) { typedef typename std::iterator_traits::value_type EdgeIndex; // Put the degree of each vertex v into m_rowstart[v + 1] for (KeyIterator i = begin; i != end; ++i) { if (key_filter(*i)) { BOOST_ASSERT (key_transform(*i) < numkeys); ++starts[key_transform(*i) + 1]; } } // Compute the partial sum of the degrees to get the actual values of // m_rowstart EdgeIndex start_of_this_row = 0; starts[0] = start_of_this_row; for (VerticesSize i = 1; i < numkeys + 1; ++i) { start_of_this_row += starts[i]; starts[i] = start_of_this_row; } } template void histogram_sort(KeyIterator key_begin, KeyIterator key_end, RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed NumKeys numkeys, Value1InputIter values1_begin, Value1OutputIter values1_out, KeyFilter key_filter, KeyTransform key_transform) { typedef typename std::iterator_traits::value_type EdgeIndex; // Histogram sort the edges by their source vertices, putting the targets // into m_column. The index current_insert_positions[v] contains the next // location to insert out edges for vertex v. std::vector current_insert_positions(rowstart, rowstart + numkeys); Value1InputIter v1i = values1_begin; for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i) { if (key_filter(*i)) { NumKeys source = key_transform(*i); BOOST_ASSERT (source < numkeys); EdgeIndex insert_pos = current_insert_positions[source]; ++current_insert_positions[source]; values1_out[insert_pos] = *v1i; } } } template void histogram_sort(KeyIterator key_begin, KeyIterator key_end, RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed NumKeys numkeys, Value1InputIter values1_begin, Value1OutputIter values1_out, Value2InputIter values2_begin, Value2OutputIter values2_out, KeyFilter key_filter, KeyTransform key_transform) { typedef typename std::iterator_traits::value_type EdgeIndex; // Histogram sort the edges by their source vertices, putting the targets // into m_column. The index current_insert_positions[v] contains the next // location to insert out edges for vertex v. std::vector current_insert_positions(rowstart, rowstart + numkeys); Value1InputIter v1i = values1_begin; Value2InputIter v2i = values2_begin; for (KeyIterator i = key_begin; i != key_end; ++i, ++v1i, ++v2i) { if (key_filter(*i)) { NumKeys source = key_transform(*i); BOOST_ASSERT (source < numkeys); EdgeIndex insert_pos = current_insert_positions[source]; ++current_insert_positions[source]; values1_out[insert_pos] = *v1i; values2_out[insert_pos] = *v2i; } } } template void histogram_sort_inplace(KeyIterator key_begin, RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed NumKeys numkeys, Value1Iter values1, KeyTransform key_transform) { typedef typename std::iterator_traits::value_type EdgeIndex; // 1. Copy m_rowstart (except last element) to get insert positions std::vector insert_positions(rowstart, rowstart + numkeys); // 2. Swap the sources and targets into place for (size_t i = 0; i < rowstart[numkeys]; ++i) { BOOST_ASSERT (key_transform(key_begin[i]) < numkeys); // While edge i is not in the right bucket: while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) { // Add a slot in the right bucket size_t target_pos = insert_positions[key_transform(key_begin[i])]++; BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]); if (target_pos == i) continue; // Swap this edge into place using std::swap; swap(key_begin[i], key_begin[target_pos]); swap(values1[i], values1[target_pos]); } } } template void histogram_sort_inplace(KeyIterator key_begin, RowstartIterator rowstart, // Must support numkeys + 1 elements and be precomputed NumKeys numkeys, Value1Iter values1, Value2Iter values2, KeyTransform key_transform) { typedef typename std::iterator_traits::value_type EdgeIndex; // 1. Copy m_rowstart (except last element) to get insert positions std::vector insert_positions(rowstart, rowstart + numkeys); // 2. Swap the sources and targets into place for (size_t i = 0; i < rowstart[numkeys]; ++i) { BOOST_ASSERT (key_transform(key_begin[i]) < numkeys); // While edge i is not in the right bucket: while (!(i >= rowstart[key_transform(key_begin[i])] && i < insert_positions[key_transform(key_begin[i])])) { // Add a slot in the right bucket size_t target_pos = insert_positions[key_transform(key_begin[i])]++; BOOST_ASSERT (target_pos < rowstart[key_transform(key_begin[i]) + 1]); if (target_pos == i) continue; // Swap this edge into place using std::swap; swap(key_begin[i], key_begin[target_pos]); swap(values1[i], values1[target_pos]); swap(values2[i], values2[target_pos]); } } } template void split_into_separate_coords(InputIterator begin, InputIterator end, std::vector& firsts, std::vector& seconds) { firsts.clear(); seconds.clear(); size_t reserve_size = detail::reserve_count_for_single_pass(begin, end); firsts.reserve(reserve_size); seconds.reserve(reserve_size); for (; begin != end; ++begin) { std::pair edge = *begin; firsts.push_back(edge.first); seconds.push_back(edge.second); } } template void split_into_separate_coords_filtered (InputIterator begin, InputIterator end, std::vector& firsts, std::vector& seconds, const SourceFilter& filter) { firsts.clear(); seconds.clear(); for (; begin != end; ++begin) { std::pair edge = *begin; if (filter(edge.first)) { firsts.push_back(edge.first); seconds.push_back(edge.second); } } } template void split_into_separate_coords_filtered (InputIterator begin, InputIterator end, PropInputIterator props, std::vector& firsts, std::vector& seconds, std::vector& props_out, const SourceFilter& filter) { firsts.clear(); seconds.clear(); props_out.clear(); for (; begin != end; ++begin) { std::pair edge = *begin; if (filter(edge.first)) { firsts.push_back(edge.first); seconds.push_back(edge.second); props_out.push_back(*props); } ++props; } } // The versions of operator()() here can't return by reference because the // actual type passed in may not match Pair, in which case the reference // parameter is bound to a temporary that could end up dangling after the // operator returns. template struct project1st { typedef typename Pair::first_type result_type; result_type operator()(const Pair& p) const {return p.first;} }; template struct project2nd { typedef typename Pair::second_type result_type; result_type operator()(const Pair& p) const {return p.second;} }; } } } #endif // BOOST_GRAPH_DETAIL_HISTOGRAM_SORT_HPP