Skip to content

Commit e48e2f2

Browse files
authored
Create maximum_flow.py
1 parent d88f630 commit e48e2f2

File tree

1 file changed

+102
-0
lines changed

1 file changed

+102
-0
lines changed

graphs/maximum_flow.py

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
""" An implementation of the Edmonds-Karp algorithm to find maximum flow. """
2+
__author__ = 'Claus Martinsen'
3+
4+
from math import inf
5+
from collections import deque
6+
7+
8+
def edmonds_karp(capacity_matrix, s, t):
9+
"""
10+
Finds the maximum flow (i.e. the maximum throughput) from node a to node b
11+
given a matrix of the capacity between the nodes.
12+
13+
The Edmonds-Karp algorithm is an implementation of the Ford-Fulkerson
14+
method.
15+
16+
:param capacity_matrix: An n*n matrix where m[i][j] indicates the capacity
17+
from node i to node j and n is the total number of nodes in the graph.
18+
:type capacity_matrix: list
19+
:param s: The source/start node.
20+
:type s: int
21+
:param t: The drain/end node.
22+
:type t: int
23+
:return: An n*n matrix of maximum flow where m[i][j] indicates the flow
24+
from node i to node j.
25+
:rtype: list
26+
"""
27+
n = len(capacity_matrix)
28+
queue = deque()
29+
flow_net = [[0 for _ in range(n)] for _ in range(n)]
30+
residual_net = [[capacity_matrix[y][x] for x in range(n)] for y in range(n)]
31+
augmenting_values = [0 if x != t else -1 for x in range(n)]
32+
33+
while augmenting_values[t] != 0: # While we find an augmenting path
34+
# Reset the values
35+
predecesor_values = [None for _ in range(n)]
36+
augmenting_values = [0 for _ in range(n)]
37+
augmenting_values[s] = inf
38+
queue.clear()
39+
queue.appendleft(s)
40+
41+
while augmenting_values[t] == 0 and queue:
42+
# While we have not augmented the drain, or run out of nodes
43+
u = queue.pop()
44+
for v in range(n): # Try to push more flow
45+
if u != v and capacity_matrix[u][v] != 0 or capacity_matrix[v][u] != 0:
46+
if capacity_matrix[u][v] != 0:
47+
residual_net[u][v] = capacity_matrix[u][v] - flow_net[u][v]
48+
else:
49+
residual_net[u][v] = flow_net[v][u]
50+
if residual_net[u][v] > 0 and augmenting_values[v] == 0:
51+
if augmenting_values[u] < residual_net[u][v]:
52+
augmenting_values[v] = augmenting_values[u]
53+
else:
54+
augmenting_values[v] = residual_net[u][v]
55+
predecesor_values[v] = u
56+
queue.appendleft(v)
57+
58+
u, v = predecesor_values[t], t
59+
while u is not None: # Update the flow in the augmenting path
60+
if capacity_matrix[u][v] != 0:
61+
flow_net[u][v] = flow_net[u][v] + augmenting_values[t]
62+
else:
63+
flow_net[v][u] = flow_net[v][u] - augmenting_values[t]
64+
u, v = predecesor_values[u], u
65+
66+
return flow_net
67+
68+
69+
def get_node_flow(flow_net, node):
70+
"""
71+
Returns the sum of the flow into minus the sum of the flow out from the
72+
node.
73+
74+
In a maximum flow network, this function returns 0 for all nodes except
75+
for the source (wich returns -max_flow) and drain (wich returns max_flow).
76+
"""
77+
flow = 0
78+
n = len(flow_net)
79+
for i in range(n):
80+
flow += flow_net[i][node]
81+
flow -= flow_net[node][i]
82+
return flow
83+
84+
85+
if __name__ == '__main__':
86+
# Only executed when this module is run directly
87+
# The following is an example of how to use the algorithm
88+
89+
a = [[0, 13, 13, 0, 0, 0],
90+
[0, 0, 0, 14, 0, 0],
91+
[0, 4, 0, 9, 12, 0],
92+
[0, 0, 0, 0, 0, 4],
93+
[0, 0, 0, 7, 0, 20],
94+
[0, 0, 0, 0, 0, 0]]
95+
96+
source_node, drain_node = 0, 5
97+
flow_network = edmonds_karp(a, source_node, drain_node)
98+
99+
for row in flow_network:
100+
print(row)
101+
102+
print('Maximum flow:', get_node_flow(flow_network, drain_node))

0 commit comments

Comments
 (0)