boost/graph/detail/histogram_sort.hpp
// 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 <boost/assert.hpp>
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