Implement Dinic Algorithm for MaximumFlow/MinimumCut
This commit is contained in:
committed by
Patrick Niklaus
parent
dd3f351874
commit
db7adfa77b
@@ -55,32 +55,34 @@ template <typename InputEdge>
|
||||
std::vector<BisectionNode> computeNodes(const std::vector<util::Coordinate> &coordinates,
|
||||
const std::vector<InputEdge> &edges)
|
||||
{
|
||||
std::vector<BisectionNode> result(coordinates.size() + 1 /*sentinel*/);
|
||||
std::vector<BisectionNode> result;
|
||||
result.reserve(coordinates.size() + 1 /*sentinel*/);
|
||||
|
||||
// stateful transform, counting node ids and moving the edge itr forward
|
||||
const auto coordinate_to_bisection_node =
|
||||
[ edge_itr = edges.begin(), node_id = 0u, &edges ](
|
||||
const util::Coordinate coordinate) mutable->BisectionNode
|
||||
{
|
||||
const auto edges_of_node = edge_itr;
|
||||
|
||||
// count all edges with this source
|
||||
// find the end of edges that belong to node_id
|
||||
const auto advance_edge_itr = [&edges](const std::size_t node_id, auto edge_itr) {
|
||||
while (edge_itr != edges.end() && edge_itr->source == node_id)
|
||||
++edge_itr;
|
||||
|
||||
// go to the next node
|
||||
++node_id;
|
||||
|
||||
return {static_cast<std::size_t>(std::distance(edges.begin(), edges_of_node)), coordinate};
|
||||
return edge_itr;
|
||||
};
|
||||
|
||||
std::transform(
|
||||
begin(coordinates), end(coordinates), begin(result), coordinate_to_bisection_node);
|
||||
// create a bisection node, requires the ID of the node as well as the lower bound to its edges
|
||||
const auto make_bisection_node = [&edges, &coordinates](const std::size_t node_id,
|
||||
const auto edge_itr) -> BisectionNode {
|
||||
return {static_cast<std::size_t>(std::distance(edges.begin(), edge_itr)),
|
||||
coordinates[node_id]};
|
||||
};
|
||||
|
||||
auto edge_itr = edges.begin();
|
||||
for (std::size_t node_id = 0; node_id < coordinates.size(); ++node_id)
|
||||
{
|
||||
result.emplace_back(make_bisection_node(node_id,edge_itr));
|
||||
edge_itr = advance_edge_itr(node_id,edge_itr);
|
||||
}
|
||||
|
||||
auto null_island = util::Coordinate(util::FloatLongitude{0.0}, util::FloatLatitude{0.0});
|
||||
auto sentinel = BisectionNode{edges.size(), std::move(null_island)};
|
||||
|
||||
result.back() = std::move(sentinel);
|
||||
result.emplace_back(std::move(sentinel));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#ifndef OSRM_PARTITION_DINIC_MAX_FLOW_HPP_
|
||||
#define OSRM_PARTITION_DINIC_MAX_FLOW_HPP_
|
||||
|
||||
#include "partition/graph_view.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template <> struct hash<std::pair<NodeID, NodeID>>
|
||||
{
|
||||
std::size_t operator()(const std::pair<NodeID, NodeID> &flow_edge) const
|
||||
{
|
||||
std::size_t combined = (static_cast<std::size_t>(flow_edge.first) << 32) | flow_edge.second;
|
||||
return std::hash<std::size_t>()(combined);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace partition
|
||||
{
|
||||
|
||||
class DinicMaxFlow
|
||||
{
|
||||
public:
|
||||
using PartitionResult = std::vector<bool>;
|
||||
using SourceSinkNodes = std::set<NodeID>;
|
||||
using LevelGraph = std::unordered_map<NodeID, std::uint32_t>;
|
||||
using FlowEdges = std::unordered_set<std::pair<NodeID, NodeID>>;
|
||||
|
||||
PartitionResult operator()(const GraphView &view,
|
||||
const SourceSinkNodes &sink_nodes,
|
||||
const SourceSinkNodes &source_nodes) const;
|
||||
|
||||
private:
|
||||
LevelGraph ComputeLevelGraph(const GraphView &view,
|
||||
const SourceSinkNodes &source_nodes,
|
||||
const FlowEdges &flow) const;
|
||||
|
||||
void AugmentFlow(FlowEdges &flow,
|
||||
const GraphView &view,
|
||||
const SourceSinkNodes &source_nodes,
|
||||
const SourceSinkNodes &sink_nodes,
|
||||
const LevelGraph &levels) const;
|
||||
|
||||
bool findPath(const NodeID from,
|
||||
std::vector<NodeID> &path,
|
||||
const GraphView &view,
|
||||
const LevelGraph &levels,
|
||||
const FlowEdges &flow,
|
||||
const SourceSinkNodes &sink_nodes) const;
|
||||
};
|
||||
|
||||
} // namespace partition
|
||||
} // namespace osrm
|
||||
|
||||
// Implementation of Dinics [1] algorithm for max-flow/min-cut.
|
||||
// [1] https://www.cs.bgu.ac.il/~dinitz/D70.pdf
|
||||
|
||||
#endif // OSRM_PARTITION_DINIC_MAX_FLOW_HPP_
|
||||
@@ -49,7 +49,7 @@ class EdgeIDIterator : public boost::iterator_facade<EdgeIDIterator,
|
||||
void decrement() { --position; }
|
||||
void advance(difference_type offset) { position += offset; }
|
||||
bool equal(const EdgeIDIterator &other) const { return position == other.position; }
|
||||
const reference dereference() const { return position; }
|
||||
reference dereference() const { return position; }
|
||||
difference_type distance_to(const EdgeIDIterator &other) const
|
||||
{
|
||||
return static_cast<difference_type>(other.position - position);
|
||||
@@ -70,7 +70,7 @@ class GraphView
|
||||
const RecursiveBisectionState::IDIterator begin,
|
||||
const RecursiveBisectionState::IDIterator end);
|
||||
|
||||
// Number of nodes _in this sub-graph_.
|
||||
// Number of nodes _in this sub-graph.
|
||||
std::size_t NumberOfNodes() const;
|
||||
|
||||
RecursiveBisectionState::IDIterator Begin() const;
|
||||
@@ -79,6 +79,8 @@ class GraphView
|
||||
EdgeIterator EdgeBegin(const NodeID nid) const;
|
||||
EdgeIterator EdgeEnd(const NodeID nid) const;
|
||||
|
||||
NodeID GetTarget(const EdgeID eid) const;
|
||||
|
||||
private:
|
||||
const BisectionGraph &bisection_graph;
|
||||
const RecursiveBisectionState &bisection_state;
|
||||
|
||||
Reference in New Issue
Block a user