From dfd743f50c00a44741e063ccfd2f7807cd67cb3c Mon Sep 17 00:00:00 2001
From: Lukas Garbas <lukasgarba@gmail.com>
Date: Tue, 14 May 2019 10:40:28 +0200
Subject: [PATCH] multiple sources and sinks

---
 bnb/edmonds_karp.cpp            | 78 ++++++++++++++++++++-------------
 include/gp-bnb/edmonds_karp.hpp | 12 ++---
 2 files changed, 53 insertions(+), 37 deletions(-)

diff --git a/bnb/edmonds_karp.cpp b/bnb/edmonds_karp.cpp
index 90c307b..b35a000 100644
--- a/bnb/edmonds_karp.cpp
+++ b/bnb/edmonds_karp.cpp
@@ -1,13 +1,12 @@
 #include <limits>
 #include <queue>
 #include <cassert>
+#include <algorithm>
 
 #include <gp-bnb/edmonds_karp.hpp>
 
-edmonds_karp::edmonds_karp(const graph &g, node_id source, node_id sink) 
-    : g_(g), source_(source), sink_(sink) {
-	assert(source_ > 0); // Nodes have ids: 1, .., n
-	assert(source_ <= g.num_nodes());
+edmonds_karp::edmonds_karp(const graph &g, std::vector<node_id> sources, std::vector<node_id> sinks) 
+    : g_(g), sources_(sources), sinks_(sinks) {
 };
 
 /* Indexes edges of the graph
@@ -37,24 +36,29 @@ void edmonds_karp::index_edges() {
 	}
 }
 
-/* Breadth-first search in the graph from source to sink
-When the sink is reached gain is added to gain[sink] */
-int edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const {
+/* Breadth-first search in the graph from source nodes to sink nodes */
+std::pair<int, node_id> edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const {
 
-    pred.clear();
-	pred.resize(g_.num_nodes() + 1, -1 ); // undiscovered nodes are marked with -1
-	std::vector<int> gain(g_.num_nodes(), 0.0);
+	pred.clear();
+	pred.resize(g_.num_nodes() + 1, -1); // undiscovered nodes are marked with -1
+	std::vector<int> gain(g_.num_nodes(), 0);
+	bool sink_reached = false;
+	node_id sink;
 
+	// Push all source nodes to the queue
 	std::queue<node_id> q;
-	q.push(source_);
-	pred[source_] = source_;
-	gain[source_] = std::numeric_limits<int>::max();
-	while (!q.empty()) {
+	for (node_id s : sources_) {
+		q.push(s);
+		pred[s] = s;
+		gain[s] = std::numeric_limits<int>::max();
+	}
+
+	// Perform BFS from each source node and stop when the sink was reached
+	// or there was no path found from the source to the sink
+	while (!q.empty() && !sink_reached) {
 		node_id u = q.front();
         q.pop();
 
-		bool sink_reached = false;
-
         std::vector<node_id> neighbors = g_.get_adjacency(u);
 
 		// iterate through neighbors of u
@@ -67,19 +71,23 @@ int edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &p
 			&& pred[v] == (unsigned int) -1) { // only add those neighbors with rest capacity and which were not discovered yet
 				pred[v] = u;
 				gain[v] = std::min(gain[u], edge_weight - (u >= v ? flow_[edge_id] : resid_flow[edge_id]));
-				if (v != sink_ && !sink_reached) {
+	
+				if (!sink_reached) {
 					q.push(v);
-				} else {
-					sink_reached = true;
+					sink = v;
 				}
+				// Check if any of the sink nodes are reached
+				for (node_id t : sinks_)
+					if (v == t) sink_reached = true;
 			}
 		}
 
-		if (sink_reached) {
-			return gain[sink_];
-		}
+		if (sink_reached)
+			return std::make_pair(gain[sink], sink);
+
 	}
-	return 0.0;
+
+	return std::make_pair(0.0, sink);
 };
 
 
@@ -91,31 +99,36 @@ Step 2: Perform BFS that returns max gain from source to sink in one path
 Step 3: Add gain that was calculated during BFS to the flow value. Break from the loop if gain was 0
 Step 4: Update flow and residual flow values for each node */
 void edmonds_karp::run() {
+
 	index_edges();
 	int num_edges = indexed_edges_.size() / 2;
 
 	flow_.clear();
-	flow_.resize(num_edges, 0.0);
-	std::vector<int> resid_flow(num_edges, 0.0);
+	flow_.resize(num_edges, 0);
+	std::vector<int> resid_flow(num_edges, 0);
 
 	flow_value_ = 0;
 
 	while (true) {
 		std::vector<node_id> pred;
-		// Perform BFS that returns max gain from source to sink in one path
-		int gain = bfs(resid_flow, pred);
 
-		// If gain == 0.0 that means there exist no more paths from source to sink
+		// BFS from source nodes to sink nodes
+		auto bfs_result = bfs(resid_flow, pred);
+		int gain = bfs_result.first;
+		node_id v = bfs_result.second;
+
 		if (gain == 0) break;
 
 		// Add gain that was calculated during BFS to the flow value
 		flow_value_ += gain;
-		node_id v = sink_;
 
-		// Update flow and residual flow values for each edge
-		while (v != source_) {
+		// Update flow and residual flow values for each edge 
+		// in the path from the sink node to the source node
+		bool source_reached = false;
+		while (!source_reached) {
 			node_id u = pred[v];
 			int edge_id = indexed_edges_[std::make_pair(u, v)];
+
 			if (u >= v) {
 				flow_[edge_id] += gain;
 				resid_flow[edge_id] -= gain;
@@ -123,9 +136,12 @@ void edmonds_karp::run() {
 				flow_[edge_id] -= gain;
 				resid_flow[edge_id] += gain;
 			}
+
 			v = u;
+			source_reached = std::find(sources_.begin(), sources_.end(), v) != sources_.end();
 		}
 	}
+	
 };
 
 int edmonds_karp::get_max_flow() const {
diff --git a/include/gp-bnb/edmonds_karp.hpp b/include/gp-bnb/edmonds_karp.hpp
index 95616fa..86e3f12 100644
--- a/include/gp-bnb/edmonds_karp.hpp
+++ b/include/gp-bnb/edmonds_karp.hpp
@@ -1,9 +1,9 @@
 #ifndef EDMONDSKARP_H_
 #define EDMONDSKARP_H_
 
-#include "graph.hpp"
 #include <vector>
 #include <map>
+#include <gp-bnb/graph.hpp>
 
 class edmonds_karp {
 private:
@@ -11,8 +11,8 @@ private:
 
 	std::map<std::pair<node_id, node_id>, unsigned int> indexed_edges_;
 
-	node_id source_;
-	node_id sink_;
+	std::vector<node_id> sources_;
+	std::vector<node_id> sinks_;
 
 	int flow_value_;
 	std::vector<int> flow_;
@@ -26,9 +26,9 @@ private:
 	 * Performs a breadth-first search on the graph from the source node to find an augmenting path to the sink node respecting the flow values
 	 * @param residFlow The residual flow in the network.
 	 * @param pred Used to store the path from the source to the sink.
-	 * @return The gain in terms of flow.
+	 * @return The gain in terms of flow and id of the sink node.
 	 */
-	int bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const;
+	std::pair<int, node_id> bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const;
 
 public:
 	/**
@@ -37,7 +37,7 @@ public:
 	 * @param source The source node.
 	 * @param sink The sink node.
 	 */
-	 edmonds_karp(const graph &g, node_id source, node_id sink);
+	 edmonds_karp(const graph &g, std::vector<node_id> sources, std::vector<node_id> sinks);
 
 	/**
 	 * Computes the maximum flow, executes the EdmondsKarp algorithm.
-- 
GitLab