320 lines
13 KiB
C++
320 lines
13 KiB
C++
// 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
|