From d0c44bf20a26bd53f804210b6e667b97a9d4d2b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Uhl=C3=ADk?= <jan@uhlik.me>
Date: Thu, 29 Mar 2018 21:05:07 +0200
Subject: [PATCH] Add Ford-Fulkerson algorithm.

---
 .../src/maximum_flow/FordFulkerson.cpp        | 224 ++++++++++++++++++
 .../src/maximum_flow/FordFulkerson.hpp        |  55 +++++
 .../src/minimum_cut/FordFulkerson.cpp         | 162 +++++++++++++
 .../src/minimum_cut/FordFulkerson.hpp         |  60 +++++
 4 files changed, 501 insertions(+)
 create mode 100644 alib2graph_algo/src/maximum_flow/FordFulkerson.cpp
 create mode 100644 alib2graph_algo/src/maximum_flow/FordFulkerson.hpp
 create mode 100644 alib2graph_algo/src/minimum_cut/FordFulkerson.cpp
 create mode 100644 alib2graph_algo/src/minimum_cut/FordFulkerson.hpp

diff --git a/alib2graph_algo/src/maximum_flow/FordFulkerson.cpp b/alib2graph_algo/src/maximum_flow/FordFulkerson.cpp
new file mode 100644
index 0000000000..d5adc4361c
--- /dev/null
+++ b/alib2graph_algo/src/maximum_flow/FordFulkerson.cpp
@@ -0,0 +1,224 @@
+// 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);
+}
diff --git a/alib2graph_algo/src/maximum_flow/FordFulkerson.hpp b/alib2graph_algo/src/maximum_flow/FordFulkerson.hpp
new file mode 100644
index 0000000000..e64fc181ae
--- /dev/null
+++ b/alib2graph_algo/src/maximum_flow/FordFulkerson.hpp
@@ -0,0 +1,55 @@
+// 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
diff --git a/alib2graph_algo/src/minimum_cut/FordFulkerson.cpp b/alib2graph_algo/src/minimum_cut/FordFulkerson.cpp
new file mode 100644
index 0000000000..07675602d6
--- /dev/null
+++ b/alib2graph_algo/src/minimum_cut/FordFulkerson.cpp
@@ -0,0 +1,162 @@
+// 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);
+}
diff --git a/alib2graph_algo/src/minimum_cut/FordFulkerson.hpp b/alib2graph_algo/src/minimum_cut/FordFulkerson.hpp
new file mode 100644
index 0000000000..497cee1af8
--- /dev/null
+++ b/alib2graph_algo/src/minimum_cut/FordFulkerson.hpp
@@ -0,0 +1,60 @@
+// 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
-- 
GitLab