Make InertialFlow a function

This commit is contained in:
Patrick Niklaus 2017-03-01 00:48:00 +00:00 committed by Patrick Niklaus
parent 54c35710f6
commit e20cbf673f
3 changed files with 36 additions and 50 deletions

View File

@ -4,42 +4,15 @@
#include "partition/dinic_max_flow.hpp" #include "partition/dinic_max_flow.hpp"
#include "partition/graph_view.hpp" #include "partition/graph_view.hpp"
#include <unordered_set>
#include <vector>
namespace osrm namespace osrm
{ {
namespace partition namespace partition
{ {
class InertialFlow DinicMaxFlow::MinCut computeInertialFlowCut(const GraphView &view,
{ const std::size_t num_slopes,
public: const double balance,
InertialFlow(const GraphView &view); const double source_sink_rate);
DinicMaxFlow::MinCut ComputePartition(const std::size_t num_slopes,
const double balance,
const double source_sink_rate);
private:
// Spatially ordered sources and sink ids.
// The node ids refer to nodes in the GraphView.
struct SpatialOrder
{
std::unordered_set<NodeID> sources;
std::unordered_set<NodeID> sinks;
};
// Creates a spatial order of n * sources "first" and n * sink "last" node ids.
// The slope determines the spatial order for sorting node coordinates.
SpatialOrder MakeSpatialOrder(double ratio, double slope) const;
// Makes n cuts with different spatial orders and returns the best.
DinicMaxFlow::MinCut BestMinCut(std::size_t n, double ratio, double balance) const;
// The subgraph to partition into two parts.
const GraphView &view;
};
} // namespace partition } // namespace partition
} // namespace osrm } // namespace osrm

View File

@ -9,7 +9,9 @@
#include <mutex> #include <mutex>
#include <set> #include <set>
#include <tuple> #include <tuple>
#include <unordered_set>
#include <utility> #include <utility>
#include <vector>
#include <tbb/blocked_range.h> #include <tbb/blocked_range.h>
#include <tbb/parallel_for.h> #include <tbb/parallel_for.h>
@ -18,18 +20,19 @@ namespace osrm
{ {
namespace partition namespace partition
{ {
namespace
InertialFlow::InertialFlow(const GraphView &view_) : view(view_) {}
DinicMaxFlow::MinCut InertialFlow::ComputePartition(const std::size_t num_slopes,
const double balance,
const double source_sink_rate)
{ {
return BestMinCut(num_slopes, source_sink_rate, balance); // Spatially ordered sources and sink ids.
} // The node ids refer to nodes in the GraphView.
struct SpatialOrder
{
std::unordered_set<NodeID> sources;
std::unordered_set<NodeID> sinks;
};
InertialFlow::SpatialOrder InertialFlow::MakeSpatialOrder(const double ratio, // Creates a spatial order of n * sources "first" and n * sink "last" node ids.
const double slope) const // The slope determines the spatial order for sorting node coordinates.
SpatialOrder makeSpatialOrder(const GraphView &view, const double ratio, const double slope)
{ {
struct NodeWithCoordinate struct NodeWithCoordinate
{ {
@ -70,7 +73,7 @@ InertialFlow::SpatialOrder InertialFlow::MakeSpatialOrder(const double ratio,
reorderFirstLast(embedding, n, spatially); reorderFirstLast(embedding, n, spatially);
InertialFlow::SpatialOrder order; SpatialOrder order;
order.sources.reserve(n); order.sources.reserve(n);
order.sinks.reserve(n); order.sinks.reserve(n);
@ -84,13 +87,14 @@ InertialFlow::SpatialOrder InertialFlow::MakeSpatialOrder(const double ratio,
return order; return order;
} }
// Makes n cuts with different spatial orders and returns the best.
DinicMaxFlow::MinCut DinicMaxFlow::MinCut
InertialFlow::BestMinCut(const std::size_t n, const double ratio, const double balance) const bestMinCut(const GraphView &view, const std::size_t n, const double ratio, const double balance)
{ {
DinicMaxFlow::MinCut best; DinicMaxFlow::MinCut best;
best.num_edges = -1; best.num_edges = -1;
const auto get_balance = [this, balance](const auto num_nodes_source) { const auto get_balance = [&view, balance](const auto num_nodes_source) {
const auto perfect_balance = view.NumberOfNodes() / 2; const auto perfect_balance = view.NumberOfNodes() / 2;
const auto allowed_balance = balance * perfect_balance; const auto allowed_balance = balance * perfect_balance;
const auto bigger_side = const auto bigger_side =
@ -108,18 +112,18 @@ InertialFlow::BestMinCut(const std::size_t n, const double ratio, const double b
tbb::blocked_range<std::size_t> range{0, n, 1}; tbb::blocked_range<std::size_t> range{0, n, 1};
const auto balance_delta = [this](const auto num_nodes_source) { const auto balance_delta = [&view](const auto num_nodes_source) {
const std::int64_t difference = const std::int64_t difference =
static_cast<std::int64_t>(view.NumberOfNodes()) / 2 - num_nodes_source; static_cast<std::int64_t>(view.NumberOfNodes()) / 2 - num_nodes_source;
return std::abs(difference); return std::abs(difference);
}; };
tbb::parallel_for(range, [&, this](const auto &chunk) { tbb::parallel_for(range, [&](const auto &chunk) {
for (auto round = chunk.begin(), end = chunk.end(); round != end; ++round) for (auto round = chunk.begin(), end = chunk.end(); round != end; ++round)
{ {
const auto slope = -1. + round * (2. / n); const auto slope = -1. + round * (2. / n);
auto order = this->MakeSpatialOrder(ratio, slope); auto order = makeSpatialOrder(view, ratio, slope);
auto cut = DinicMaxFlow()(view, order.sources, order.sinks); auto cut = DinicMaxFlow()(view, order.sources, order.sinks);
auto cut_balance = get_balance(cut.num_nodes_source); auto cut_balance = get_balance(cut.num_nodes_source);
@ -141,6 +145,15 @@ InertialFlow::BestMinCut(const std::size_t n, const double ratio, const double b
return best; return best;
} }
}
DinicMaxFlow::MinCut computeInertialFlowCut(const GraphView &view,
const std::size_t num_slopes,
const double balance,
const double source_sink_rate)
{
return bestMinCut(view, num_slopes, source_sink_rate, balance);
}
} // namespace partition } // namespace partition
} // namespace osrm } // namespace osrm

View File

@ -70,10 +70,10 @@ RecursiveBisection::RecursiveBisection(BisectionGraph &bisection_graph_,
// Bisect graph into two parts. Get partition point and recurse left and right in parallel. // Bisect graph into two parts. Get partition point and recurse left and right in parallel.
tbb::parallel_do(begin(forest), end(forest), [&](const TreeNode &node, Feeder &feeder) { tbb::parallel_do(begin(forest), end(forest), [&](const TreeNode &node, Feeder &feeder) {
InertialFlow flow{node.graph}; const auto cut =
const auto partition = flow.ComputePartition(num_optimizing_cuts, balance, boundary_factor); computeInertialFlowCut(node.graph, num_optimizing_cuts, balance, boundary_factor);
const auto center = internal_state.ApplyBisection( const auto center = internal_state.ApplyBisection(
node.graph.Begin(), node.graph.End(), node.depth, partition.flags); node.graph.Begin(), node.graph.End(), node.depth, cut.flags);
const auto terminal = [&](const auto &node) { const auto terminal = [&](const auto &node) {
const auto maximum_depth = sizeof(BisectionID) * CHAR_BIT; const auto maximum_depth = sizeof(BisectionID) * CHAR_BIT;