Skip to content
Snippets Groups Projects
Commit d0c44bf2 authored by Jan Uhlík's avatar Jan Uhlík Committed by Jan Trávníček
Browse files

Add Ford-Fulkerson algorithm.

parent 3a5ba7da
No related branches found
No related tags found
No related merge requests found
// FordFulkerson.cpp
//
// Created on: 29. 03. 2016
// Author: Jan Broz
// Modified by: Jan Uhlik
//
// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
#include "FordFulkerson.hpp"
#include <queue>
#include <climits>
#include <registration/AlgoRegistration.hpp>
namespace maximum_flow {
enum State { FRESH, OPEN, CLOSED };
struct Context {
Capacity capacity;
Flow flow;
ext::unordered_map<node::Node, node::Node> prev;
ext::unordered_map<node::Node, int> sgn;
ext::unordered_map<node::Node, int> maxFlowTo;
};
static Capacity getCapacity(const DirectedGraph &graph) {
Capacity capacity;
for (const auto &edge : graph.getEdges()) {
capacity[edge.first][edge.second] = edge.capacity();
}
return capacity;
}
static bool findPath_dir(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink,
Context &ctx) {
ext::unordered_map<node::Node, State> state;
std::queue<node::Node> open;
node::Node actual;
for (const node::Node &node : graph.getNodes()) {
state[node] = FRESH;
ctx.maxFlowTo[node] = 0;
}
ctx.maxFlowTo[source] = INT_MAX;
ctx.prev[source] = source;
state[source] = OPEN;
open.push(source);
do {
actual = open.front();
open.pop();
state[actual] = CLOSED;
for (const node::Node &succ : graph.successors(actual)) {
if (state[succ] == FRESH && ctx.flow[actual][succ] < ctx.capacity[actual][succ]) {
state[succ] = OPEN;
open.push(succ);
ctx.prev[succ] = actual;
ctx.sgn[succ] = 1;
ctx.maxFlowTo[succ] = std::min(ctx.maxFlowTo[actual], ctx.capacity[actual][succ] - ctx.flow[actual][succ]);
}
}
for (const node::Node &pred : graph.predecessors(actual)) {
if (state[pred] == FRESH && ctx.flow[pred][actual] > 0) {
state[pred] = OPEN;
open.push(pred);
ctx.prev[pred] = actual;
ctx.sgn[pred] = -1;
ctx.maxFlowTo[pred] = std::min(ctx.maxFlowTo[actual], ctx.flow[pred][actual]);
}
}
} while (!open.empty() && actual != sink);
return actual == sink;
}
static bool findPath_undir(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink,
Context &ctx) {
ext::unordered_map<node::Node, State> state;
std::queue<node::Node> open;
node::Node actual;
for (const node::Node &node : graph.getNodes()) {
state[node] = FRESH;
ctx.maxFlowTo[node] = 0;
}
ctx.maxFlowTo[source] = INT_MAX;
ctx.prev[source] = source;
state[source] = OPEN;
open.push(source);
do {
actual = open.front();
open.pop();
state[actual] = CLOSED;
for (const node::Node &succ : graph.successors(actual)) {
if (state[succ] == FRESH && ctx.flow[actual][succ] < ctx.capacity[actual][succ]) {
state[succ] = OPEN;
open.push(succ);
ctx.prev[succ] = actual;
ctx.maxFlowTo[succ] = std::min(ctx.maxFlowTo[actual], ctx.capacity[actual][succ] - ctx.flow[actual][succ]);
}
}
} while (!open.empty() && actual != sink);
return actual == sink;
}
static void updateFlow_dir(const node::Node &source, const node::Node &sink, Context &ctx) {
/* alternative for finding the increase of flow
int path_flow = INT_MAX;
for (v=t; v!=s; v=parent[v])
{
u = parent[v];
path_flow = min(path_flow, rGraph[u][v]);
}
*/
int pathFlow = ctx.maxFlowTo[sink];
node::Node actual = sink;
while (actual != source) {
node::Node prev = ctx.prev[actual];
if (ctx.sgn[actual] > 0)
ctx.flow[prev][actual] += pathFlow;
else
ctx.flow[actual][prev] -= pathFlow;
actual = prev;
}
}
static void updateFlow_undir(const node::Node &source, const node::Node &sink, Context &ctx) {
int pathFlow = ctx.maxFlowTo[sink];
node::Node actual = sink;
while (actual != source) {
node::Node prev = ctx.prev[actual];
ctx.flow[prev][actual] += pathFlow;
ctx.flow[actual][prev] -= pathFlow;
actual = prev;
}
}
static Flow fordfulkerson_impl_dir(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink) {
Context ctx;
ctx.capacity = getCapacity(graph);
for (const auto &edge : graph.getEdges()) {
ctx.flow[edge.first][edge.second] = 0;
ctx.flow[edge.second][edge.first] = 0;
}
while (findPath_dir(graph, source, sink, ctx))
updateFlow_dir(source, sink, ctx);
// assign negative flow for the reversed pairs of nodes ?
for (auto u : ctx.flow)
for (auto v : u.second)
if (ctx.flow[u.first][v.first] != 0)
ctx.flow[v.first][u.first] = -ctx.flow[u.first][v.first];
return ctx.flow;
}
static Flow fordfulkerson_impl_undir(const UndirectedGraph &ugraph, node::Node source, node::Node sink) {
DirectedGraph graph;
for (auto &node: ugraph.getNodes()) {
graph.addNode(node);
}
for (auto &edge: ugraph.getEdges()) {
graph.addEdge(edge.first, edge.second, edge.capacity());
}
Context ctx;
ctx.capacity = getCapacity(graph);
for (const auto &edge : graph.getEdges()) {
ctx.flow[edge.first][edge.second] = 0;
}
while (findPath_undir(graph, source, sink, ctx))
updateFlow_undir(source, sink, ctx);
return ctx.flow;
}
Flow FordFulkerson::findMaximumFlow(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink) {
return fordfulkerson_impl_dir(graph, source, sink);
}
Flow FordFulkerson::findMaximumFlow(const UndirectedGraph &graph,
const node::Node &source,
const node::Node &sink) {
return fordfulkerson_impl_undir(graph, source, sink);
}
// ---------------------------------------------------------------------------------------------------------------------
} // namespace maximum_flow
// ---------------------------------------------------------------------------------------------------------------------
namespace {
auto FordFulkersonUndirected = registration::AbstractRegister<maximum_flow::FordFulkerson,
maximum_flow::Flow,
const maximum_flow::UndirectedGraph &,
const node::Node &,
const node::Node &>(
maximum_flow::FordFulkerson::findMaximumFlow);
auto FordFulkersonDirected = registration::AbstractRegister<maximum_flow::FordFulkerson,
maximum_flow::Flow,
const maximum_flow::DirectedGraph &,
const node::Node &,
const node::Node &>(
maximum_flow::FordFulkerson::findMaximumFlow);
}
// FordFulkerson.hpp
//
// Created on: 29. 03. 2016
// Author: Jan Broz
// Modified by: Jan Uhlik
//
// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
#ifndef ALIB2_FORDFULKERSON_HPP
#define ALIB2_FORDFULKERSON_HPP
// ---------------------------------------------------------------------------------------------------------------------
#include <alib/unordered_map>
#include <graph/GraphClasses.hpp>
#include <node/NodeClasses.hpp>
#include <edge/EdgeClasses.hpp>
namespace maximum_flow {
typedef ext::unordered_map<node::Node, ext::unordered_map<node::Node, int> > Capacity;
typedef ext::unordered_map<node::Node, ext::unordered_map<node::Node, int> > Flow;
// Old implementation without templates
using UndirectedGraph = graph::UndirectedGraph<node::Node, edge::CapacityEdge<node::Node, int>>;
using DirectedGraph = graph::DirectedGraph<node::Node, edge::CapacityEdge<node::Node, int>>;
// ---------------------------------------------------------------------------------------------------------------------
class FordFulkerson {
public:
// ---------------------------------------------------------------------------------------------------------------------
static Flow findMaximumFlow(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink);
static Flow findMaximumFlow(const UndirectedGraph &graph,
const node::Node &source,
const node::Node &sink);
// ---------------------------------------------------------------------------------------------------------------------
};
// =====================================================================================================================
// ---------------------------------------------------------------------------------------------------------------------
} // namespace maximum_flow
#endif //ALIB2_FORDFULKERSON_HPP
// FordFulkerson.cpp
//
// Created on: 29. 03. 2016
// Author: Jan Broz
// Modified by: Jan Uhlik
//
// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
#include "FordFulkerson.hpp"
#include <unordered_map> // return value
#include <queue> // BFS
#include <alib/iostream>
#include <maximum_flow/FordFulkerson.hpp>
#include <registration/AlgoRegistration.hpp>
namespace minimum_cut {
static maximum_flow::Capacity getCapacity(const DirectedGraph &graph) {
maximum_flow::Capacity capacity;
for (const auto &edge : graph.getEdges()) {
capacity[edge.first][edge.second] = edge.capacity();
}
return capacity;
}
static maximum_flow::Capacity getCapacity(const UndirectedGraph &graph) {
maximum_flow::Capacity capacity;
for (const auto &edge : graph.getEdges()) {
capacity[edge.first][edge.second] = edge.capacity();
capacity[edge.second][edge.first] = edge.capacity();
}
return capacity;
}
static Cut fordfulkerson_impl_dir(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink) {
Cut cut;
maximum_flow::Capacity capacity = getCapacity(graph);
maximum_flow::Flow flow = maximum_flow::FordFulkerson::findMaximumFlow(graph, source, sink);
// mark nodes, which are reachable from source
ext::unordered_map<node::Node, int> state;
std::queue<node::Node> open;
ext::vector<std::pair<node::Node, node::Node>> candidates;
for (const node::Node &node : graph.getNodes())
state[node] = 0;
state[source] = 1;
open.push(source);
while (!open.empty()) {
node::Node actual = open.front();
open.pop();
for (const node::Node &succ : graph.successors(actual)) {
if (state[succ] == 0 && flow[actual][succ] < capacity[actual][succ]) {
state[succ] = 1;
open.push(succ);
} else if (flow[actual][succ] == capacity[actual][succ]) {
candidates.push_back({actual, succ});
}
}
for (const node::Node &pred : graph.predecessors(actual)) {
if (state[pred] == 0 && flow[pred][actual] > 0) {
state[pred] = 1;
open.push(pred);
} else if (flow[pred][actual] == 0) {
candidates.push_back({pred, actual});
}
}
}
// cut are those edges, which lead from nodes reachable from source to nodes unreachable from source
for (std::pair<node::Node, node::Node> edge : candidates) {
if ((state[edge.first] == 1 && state[edge.second] == 0)
|| (state[edge.first] == 0 && state[edge.second] == 1))
cut.insert(edge);
}
return cut;
}
static Cut fordfulkerson_impl_undir(const UndirectedGraph &ugraph,
const node::Node &source,
const node::Node &sink) {
Cut cut;
maximum_flow::Capacity capacity = getCapacity(ugraph);
maximum_flow::Flow flow = maximum_flow::FordFulkerson::findMaximumFlow(ugraph, source, sink);
// mark nodes, which are reachable from source
ext::unordered_map<node::Node, int> state;
std::queue<node::Node> open;
ext::vector<std::pair<node::Node, node::Node>> candidates;
for (const node::Node &node : ugraph.getNodes())
state[node] = 0;
state[source] = 1;
open.push(source);
while (!open.empty()) {
node::Node actual = open.front();
open.pop();
for (const node::Node &neigh : ugraph.successors(actual)) {
if (state[neigh] == 0 && flow[actual][neigh] < capacity[actual][neigh]) {
state[neigh] = 1;
open.push(neigh);
} else if (flow[actual][neigh] == capacity[actual][neigh]) {
candidates.push_back({actual, neigh});
}
}
}
// cut are those edges, which lead from nodes reachable from source to nodes unreachable from source
for (std::pair<node::Node, node::Node> edge : candidates) {
if ((state[edge.first] == 1 && state[edge.second] == 0)
|| (state[edge.first] == 0 && state[edge.second] == 1))
cut.insert(edge);
}
return cut;
}
Cut FordFulkerson::findMinimumCut(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink) {
return fordfulkerson_impl_dir(graph, source, sink);
}
Cut FordFulkerson::findMinimumCut(const UndirectedGraph &graph,
const node::Node &source,
const node::Node &sink) {
return fordfulkerson_impl_undir(graph, source, sink);
}
//auto BasicAlgorithmUndirectedGraph = registration::OverloadRegister < FordFulkerson, UndirectedGraph, UndirectedGraph > ( FordFulkerson::findMinimumCut );
} // namespace minimumcut
// ---------------------------------------------------------------------------------------------------------------------
namespace {
auto FordFulkersonUndirected = registration::AbstractRegister<minimum_cut::FordFulkerson,
minimum_cut::Cut,
const minimum_cut::UndirectedGraph &,
const node::Node &,
const node::Node &>(
minimum_cut::FordFulkerson::findMinimumCut);
auto FordFulkersonDirected = registration::AbstractRegister<minimum_cut::FordFulkerson,
minimum_cut::Cut,
const minimum_cut::DirectedGraph &,
const node::Node &,
const node::Node &>(
minimum_cut::FordFulkerson::findMinimumCut);
}
// FordFulkerson.hpp
//
// Created on: 29. 03. 2016
// Author: Jan Broz
// Modified by: Jan Uhlik
//
// Copyright (c) 2017 Czech Technical University in Prague | Faculty of Information Technology. All rights reserved.
// Git repository: https://gitlab.fit.cvut.cz/algorithms-library-toolkit/automata-library
#ifndef ALIB2_FORDFULKERSONCUT_HPP
#define ALIB2_FORDFULKERSONCUT_HPP
#include <unordered_set>
#include <graph/GraphClasses.hpp>
#include <node/NodeClasses.hpp>
#include <edge/EdgeClasses.hpp>
namespace std {
template<>
struct hash<std::pair<node::Node, node::Node> > {
std::size_t operator()(const std::pair<node::Node, node::Node> &p) const {
return std::hash<std::string>()(static_cast<std::string>(p.first) + static_cast<std::string>(p.second));
}
};
}
// =====================================================================================================================
namespace minimum_cut {
typedef std::unordered_set<std::pair<node::Node, node::Node> > Cut;
// Old implementation without templates
using UndirectedGraph = graph::UndirectedGraph<node::Node, edge::CapacityEdge<node::Node, int>>;
using DirectedGraph = graph::DirectedGraph<node::Node, edge::CapacityEdge<node::Node, int>>;
class FordFulkerson {
public:
// ---------------------------------------------------------------------------------------------------------------------
static Cut findMinimumCut(const DirectedGraph &graph,
const node::Node &source,
const node::Node &sink);
static Cut findMinimumCut(const UndirectedGraph &graph,
const node::Node &source,
const node::Node &sink);
// ---------------------------------------------------------------------------------------------------------------------
};
// =====================================================================================================================
// ---------------------------------------------------------------------------------------------------------------------
} // namespace minimum_cut
#endif //ALIB2_FORDFULKERSONCUT_HPP
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment