2018-02-01 10:47:43 -05:00
|
|
|
|
#ifndef OSRM_PARTITIONER_DINIC_MAX_FLOW_HPP_
|
|
|
|
|
#define OSRM_PARTITIONER_DINIC_MAX_FLOW_HPP_
|
2017-01-25 05:29:37 -05:00
|
|
|
|
|
2018-02-01 10:47:43 -05:00
|
|
|
|
#include "partitioner/bisection_graph_view.hpp"
|
2017-01-25 05:29:37 -05:00
|
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <set>
|
|
|
|
|
#include <unordered_set>
|
|
|
|
|
#include <utility>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2022-12-11 04:10:26 -05:00
|
|
|
|
namespace osrm::partitioner
|
2017-01-25 05:29:37 -05:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
class DinicMaxFlow
|
|
|
|
|
{
|
|
|
|
|
public:
|
2017-02-01 09:50:06 -05:00
|
|
|
|
// maximal number of hops in the graph from source to sink
|
2017-01-26 04:34:01 -05:00
|
|
|
|
using Level = std::uint32_t;
|
2017-02-01 09:50:06 -05:00
|
|
|
|
|
2017-01-26 04:34:01 -05:00
|
|
|
|
using MinCut = struct
|
2017-01-25 04:42:13 -05:00
|
|
|
|
{
|
2017-01-26 04:34:01 -05:00
|
|
|
|
std::size_t num_nodes_source;
|
2017-01-25 04:42:13 -05:00
|
|
|
|
std::size_t num_edges;
|
|
|
|
|
std::vector<bool> flags;
|
|
|
|
|
};
|
2017-02-01 09:50:06 -05:00
|
|
|
|
|
|
|
|
|
// input parameter storing the set o
|
2017-01-26 04:34:01 -05:00
|
|
|
|
using SourceSinkNodes = std::unordered_set<NodeID>;
|
2017-01-25 05:29:37 -05:00
|
|
|
|
|
2017-08-22 15:52:42 -04:00
|
|
|
|
MinCut operator()(const BisectionGraphView &view,
|
2017-02-02 09:53:42 -05:00
|
|
|
|
const SourceSinkNodes &source_nodes,
|
|
|
|
|
const SourceSinkNodes &sink_nodes) const;
|
|
|
|
|
|
|
|
|
|
// validates the inpiut parameters to the flow algorithm (e.g. not intersecting)
|
2017-08-22 15:52:42 -04:00
|
|
|
|
bool Validate(const BisectionGraphView &view,
|
2017-02-02 09:53:42 -05:00
|
|
|
|
const SourceSinkNodes &source_nodes,
|
|
|
|
|
const SourceSinkNodes &sink_nodes) const;
|
2017-01-25 05:29:37 -05:00
|
|
|
|
|
|
|
|
|
private:
|
2017-02-01 09:50:06 -05:00
|
|
|
|
// the level of each node in the graph (==hops in BFS from source)
|
|
|
|
|
using LevelGraph = std::vector<Level>;
|
|
|
|
|
|
|
|
|
|
// this is actually faster than using an unordered_set<Edge>, stores all edges that have
|
|
|
|
|
// capacity grouped by node
|
|
|
|
|
using FlowEdges = std::vector<std::set<NodeID>>;
|
|
|
|
|
|
|
|
|
|
// The level graph (see [1]) is based on a BFS computation. We assign a level to all nodes
|
|
|
|
|
// (starting with 0 for all source nodes) and assign the hop distance in the residual graph as
|
|
|
|
|
// the level of the node.
|
|
|
|
|
// a
|
2017-02-15 04:19:33 -05:00
|
|
|
|
// / \
|
2017-02-01 09:50:06 -05:00
|
|
|
|
// s t
|
|
|
|
|
// \ /
|
|
|
|
|
// b
|
|
|
|
|
// would assign s = 0, a,b = 1, t=2
|
2017-08-22 15:52:42 -04:00
|
|
|
|
LevelGraph ComputeLevelGraph(const BisectionGraphView &view,
|
2017-01-26 04:34:01 -05:00
|
|
|
|
const std::vector<NodeID> &border_source_nodes,
|
2017-01-25 05:29:37 -05:00
|
|
|
|
const SourceSinkNodes &source_nodes,
|
2017-01-26 04:34:01 -05:00
|
|
|
|
const SourceSinkNodes &sink_nodes,
|
2017-01-25 05:29:37 -05:00
|
|
|
|
const FlowEdges &flow) const;
|
|
|
|
|
|
2017-02-01 09:50:06 -05:00
|
|
|
|
// Using the above levels (see ComputeLevelGraph), we can use multiple DFS (that can now be
|
|
|
|
|
// directed at the sink) to find a flow that completely blocks the level graph (i.e. no path
|
|
|
|
|
// with increasing level exists from `s` to `t`).
|
|
|
|
|
std::size_t BlockingFlow(FlowEdges &flow,
|
|
|
|
|
LevelGraph &levels,
|
2017-08-22 15:52:42 -04:00
|
|
|
|
const BisectionGraphView &view,
|
2017-02-01 09:50:06 -05:00
|
|
|
|
const SourceSinkNodes &source_nodes,
|
|
|
|
|
const std::vector<NodeID> &border_sink_nodes) const;
|
2017-01-25 05:29:37 -05:00
|
|
|
|
|
2017-02-01 09:50:06 -05:00
|
|
|
|
// Finds a single augmenting path from a node to the sink side following levels in the level
|
|
|
|
|
// graph. We don't actually remove the edges, so we have to check for increasing level values.
|
|
|
|
|
// Since we know which sinks have been reached, we actually search for these paths starting at
|
|
|
|
|
// sink nodes, instead of the source, so we can save a few dfs runs
|
2017-01-26 04:34:01 -05:00
|
|
|
|
std::vector<NodeID> GetAugmentingPath(LevelGraph &levels,
|
|
|
|
|
const NodeID from,
|
2017-08-22 15:52:42 -04:00
|
|
|
|
const BisectionGraphView &view,
|
2017-01-26 04:34:01 -05:00
|
|
|
|
const FlowEdges &flow,
|
2017-02-01 09:50:06 -05:00
|
|
|
|
const SourceSinkNodes &source_nodes) const;
|
2017-01-26 04:34:01 -05:00
|
|
|
|
|
|
|
|
|
// Builds an actual cut result from a level graph
|
2017-08-20 19:24:05 -04:00
|
|
|
|
MinCut MakeCut(const BisectionGraphView &view,
|
|
|
|
|
const LevelGraph &levels,
|
|
|
|
|
const std::size_t flow_value) const;
|
2017-01-25 05:29:37 -05:00
|
|
|
|
};
|
|
|
|
|
|
2022-12-20 12:00:11 -05:00
|
|
|
|
} // namespace osrm::partitioner
|
2017-01-25 05:29:37 -05:00
|
|
|
|
|
|
|
|
|
// Implementation of Dinics [1] algorithm for max-flow/min-cut.
|
|
|
|
|
// [1] https://www.cs.bgu.ac.il/~dinitz/D70.pdf
|
|
|
|
|
|
2018-02-01 10:47:43 -05:00
|
|
|
|
#endif // OSRM_PARTITIONER_DINIC_MAX_FLOW_HPP_
|