Implement Parallel Spatial-Ordering/Cut Selection

Extends explanation for recursive bisection ids
Cleans up Bisection State
Removes license boilerplate from partitioner config
Sorts Spatially and picks Sources and Sinks
Uses sets for sources and sinks for now; see how large they will get
Runs n cuts in parallel changing the slope and uses the best
Clarifies balance <-> ratio naming
This commit is contained in:
Daniel J. Hofmann
2017-01-25 10:42:13 +01:00
committed by Patrick Niklaus
parent db7adfa77b
commit dd60ae31ae
9 changed files with 231 additions and 38 deletions
+10
View File
@@ -71,5 +71,15 @@ NodeID GraphView::GetTarget(const EdgeID eid) const
return bisection_graph.GetTarget(eid);
}
const BisectionNode &GraphView::GetNode(const NodeID nid) const
{
return bisection_graph.GetNode(nid);
}
const BisectionEdge &GraphView::GetEdge(const EdgeID eid) const
{
return bisection_graph.GetEdge(eid);
}
} // namespace partition
} // namespace osrm
+102 -22
View File
@@ -1,10 +1,18 @@
#include "partition/inertial_flow.hpp"
#include "partition/bisection_graph.hpp"
#include "partition/dinic_max_flow.hpp"
#include "partition/reorder_first_last.hpp"
#include <cstddef>
#include <set>
#include <algorithm>
#include <cmath>
#include <bitset>
#include <cstddef>
#include <iterator>
#include <mutex>
#include <set>
#include <utility>
#include <tbb/blocked_range.h>
#include <tbb/parallel_for.h>
namespace osrm
{
@@ -13,30 +21,102 @@ namespace partition
InertialFlow::InertialFlow(const GraphView &view_) : view(view_) {}
std::vector<bool> InertialFlow::ComputePartition(const double balance, const double source_sink_rate)
std::vector<bool> InertialFlow::ComputePartition(const double balance,
const double source_sink_rate)
{
std::set<NodeID> sources;
std::set<NodeID> sinks;
auto cut = bestMinCut(10 /* should be taken from outside */, source_sink_rate);
std::size_t count = std::ceil(source_sink_rate * view.NumberOfNodes());
auto itr = view.Begin();
auto itr_end = view.End();
while(count--)
{
--itr_end;
sinks.insert(*itr_end);
sources.insert(*itr);
++itr;
}
std::cout << "Running Flow" << std::endl;
auto result = DinicMaxFlow()(view,sources,sinks);
std::cout << "Partition: ";
for( auto b : result)
for (auto b : cut.flags)
std::cout << b;
std::cout << std::endl;
return result;
return cut.flags;
}
InertialFlow::SpatialOrder InertialFlow::MakeSpatialOrder(const double ratio,
const double slope) const
{
struct NodeWithCoordinate
{
NodeWithCoordinate(NodeID nid_, util::Coordinate coordinate_)
: nid{nid_}, coordinate{std::move(coordinate_)}
{
}
NodeID nid;
util::Coordinate coordinate;
};
using Embedding = std::vector<NodeWithCoordinate>;
Embedding embedding;
embedding.reserve(view.NumberOfNodes());
std::transform(view.Begin(), view.End(), std::back_inserter(embedding), [&](const auto nid) {
return NodeWithCoordinate{nid, view.GetNode(nid).coordinate};
});
const auto project = [slope](const auto &each) {
auto lon = static_cast<std::int32_t>(each.coordinate.lon);
auto lat = static_cast<std::int32_t>(each.coordinate.lat);
return slope * lon + (1. - std::fabs(slope)) * lat;
};
const auto spatially = [&](const auto &lhs, const auto &rhs) {
return project(lhs) < project(rhs);
};
const std::size_t n = ratio * embedding.size();
reorderFirstLast(embedding, n, spatially);
InertialFlow::SpatialOrder order;
order.sources.reserve(n);
order.sinks.reserve(n);
for (auto it = begin(embedding), last = begin(embedding) + n; it != last; ++it)
order.sources.insert(it->nid);
for (auto it = end(embedding) - n, last = end(embedding); it != last; ++it)
order.sinks.insert(it->nid);
return order;
}
MinCut InertialFlow::bestMinCut(const std::size_t n, const double ratio) const
{
auto base = MakeSpatialOrder(ratio, -1.);
auto best = DinicMaxFlow()(view, base.sources, base.sinks);
std::mutex lock;
tbb::blocked_range<std::size_t> range{1, n + 1};
tbb::parallel_for(range, [&, this](const auto &chunk) {
for (auto round = chunk.begin(), end = chunk.end(); round != end; ++round)
{
const auto slope = -1. + round * (2. / n);
auto order = this->MakeSpatialOrder(ratio, slope);
auto cut = Dinic(view, order.sources, order.sinks);
auto cut = DinicMaxFlow()(view, order.sources, order.sinks);
{
std::lock_guard<std::mutex> guard{lock};
// Swap to keep the destruction of the old object outside of critical section.
if (cut.num_edges < best.num_edges)
std::swap(best, cut);
}
// cut gets destroyed here
}
});
return best;
}
} // namespace partition
+17 -12
View File
@@ -2,9 +2,9 @@
#include <numeric>
//TODO remove
#include <iostream>
// TODO remove
#include <bitset>
#include <iostream>
namespace osrm
{
@@ -15,20 +15,20 @@ RecursiveBisectionState::RecursiveBisectionState(const BisectionGraph &bisection
: bisection_graph(bisection_graph_)
{
id_array.resize(bisection_graph.GetNumberOfNodes());
std::iota(id_array.begin(), id_array.end(), 0);
bisection_ids.resize(bisection_graph.GetNumberOfNodes(), 0);
std::iota(id_array.begin(), id_array.end(), NodeID{0});
bisection_ids.resize(bisection_graph.GetNumberOfNodes(), BisectionID{0});
}
RecursiveBisectionState::~RecursiveBisectionState()
{
std::cout << "Internal Result\n";
std::cout << "IDArray:";
for( auto id : id_array )
for (auto id : id_array)
std::cout << " " << id;
std::cout << std::endl;
std::cout << "BisectionIDs:";
for( auto id : bisection_ids)
for (auto id : bisection_ids)
std::cout << " " << (std::bitset<4>(id));
std::cout << std::endl;
@@ -36,12 +36,12 @@ RecursiveBisectionState::~RecursiveBisectionState()
const RecursiveBisectionState::IDIterator RecursiveBisectionState::Begin() const
{
return id_array.begin();
return id_array.cbegin();
}
const RecursiveBisectionState::IDIterator RecursiveBisectionState::End() const
{
return id_array.end();
return id_array.cend();
}
RecursiveBisectionState::BisectionID RecursiveBisectionState::GetBisectionID(const NodeID nid) const
@@ -59,10 +59,15 @@ RecursiveBisectionState::IDIterator RecursiveBisectionState::ApplyBisection(
bisection_ids[*itr] |= partition[std::distance(begin, itr)];
}
// keep items with `0` as partition id to the left, move other to the right
return std::stable_partition(id_array.begin() + std::distance(id_array.cbegin(), begin),
id_array.begin() + std::distance(id_array.cbegin(), end),
[this](const auto nid) { return 0 == (bisection_ids[nid] & 1); });
auto first = id_array.begin() + std::distance(id_array.cbegin(), begin);
auto last = id_array.begin() + std::distance(id_array.cbegin(), end);
// Keep items with `0` as partition id to the left, move other to the right
auto by_last_bit = [this](const auto nid) {
return BisectionID{0} == (bisection_ids[nid] & 1);
};
return std::stable_partition(first, last, by_last_bit);
}
} // namespace partition