// 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 < typename InputIterator > 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 < typename InputIterator > size_t reserve_count_for_single_pass_helper(InputIterator first, InputIterator last, std::random_access_iterator_tag) { using std::distance; typename std::iterator_traits< InputIterator >::difference_type n = distance(first, last); return (size_t)n; } template < typename InputIterator > size_t reserve_count_for_single_pass( InputIterator first, InputIterator last) { typedef typename std::iterator_traits< InputIterator >::iterator_category category; return reserve_count_for_single_pass_helper( first, last, category()); } template < typename KeyIterator, typename RowstartIterator, typename VerticesSize, typename KeyFilter, typename KeyTransform > 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< RowstartIterator >::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 < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1InputIter, typename Value1OutputIter, typename KeyFilter, typename KeyTransform > 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< RowstartIterator >::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< EdgeIndex > 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 < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1InputIter, typename Value1OutputIter, typename Value2InputIter, typename Value2OutputIter, typename KeyFilter, typename KeyTransform > 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< RowstartIterator >::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< EdgeIndex > 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 < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1Iter, typename KeyTransform > 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< RowstartIterator >::value_type EdgeIndex; // 1. Copy m_rowstart (except last element) to get insert positions std::vector< EdgeIndex > 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 < typename KeyIterator, typename RowstartIterator, typename NumKeys, typename Value1Iter, typename Value2Iter, typename KeyTransform > 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< RowstartIterator >::value_type EdgeIndex; // 1. Copy m_rowstart (except last element) to get insert positions std::vector< EdgeIndex > 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 < typename InputIterator, typename VerticesSize > void split_into_separate_coords(InputIterator begin, InputIterator end, std::vector< VerticesSize >& firsts, std::vector< VerticesSize >& 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< VerticesSize, VerticesSize > edge = *begin; firsts.push_back(edge.first); seconds.push_back(edge.second); } } template < typename InputIterator, typename VerticesSize, typename SourceFilter > void split_into_separate_coords_filtered(InputIterator begin, InputIterator end, std::vector< VerticesSize >& firsts, std::vector< VerticesSize >& seconds, const SourceFilter& filter) { firsts.clear(); seconds.clear(); for (; begin != end; ++begin) { std::pair< VerticesSize, VerticesSize > edge = *begin; if (filter(edge.first)) { firsts.push_back(edge.first); seconds.push_back(edge.second); } } } template < typename InputIterator, typename PropInputIterator, typename VerticesSize, typename PropType, typename SourceFilter > void split_into_separate_coords_filtered(InputIterator begin, InputIterator end, PropInputIterator props, std::vector< VerticesSize >& firsts, std::vector< VerticesSize >& seconds, std::vector< PropType >& props_out, const SourceFilter& filter) { firsts.clear(); seconds.clear(); props_out.clear(); for (; begin != end; ++begin) { std::pair< VerticesSize, VerticesSize > 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 < typename Pair > struct project1st { typedef typename Pair::first_type result_type; result_type operator()(const Pair& p) const { return p.first; } }; template < typename Pair > 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