Skip to content

Commit 2fc2ae3

Browse files
viraatdaspoyea
authored andcommitted
Created a generalized algo to edmonds karp (TheAlgorithms#724)
Edmonds Karp algorithm is traditionally with only one source and one sink. What do you do if you have multiple sources and sinks? This algorithm is a generalized algorithm that regardless of however many sinks and sources you have, will allow you to use this algorithm. It does this by using the traditional algorithm but adding an artificial source and sink that allows with "infinite" weight.
1 parent df04d94 commit 2fc2ae3

File tree

1 file changed

+182
-0
lines changed

1 file changed

+182
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
class FlowNetwork:
2+
def __init__(self, graph, sources, sinks):
3+
self.sourceIndex = None
4+
self.sinkIndex = None
5+
self.graph = graph
6+
7+
self._normalizeGraph(sources, sinks)
8+
self.verticesCount = len(graph)
9+
self.maximumFlowAlgorithm = None
10+
11+
# make only one source and one sink
12+
def _normalizeGraph(self, sources, sinks):
13+
if sources is int:
14+
sources = [sources]
15+
if sinks is int:
16+
sinks = [sinks]
17+
18+
if len(sources) == 0 or len(sinks) == 0:
19+
return
20+
21+
self.sourceIndex = sources[0]
22+
self.sinkIndex = sinks[0]
23+
24+
# make fake vertex if there are more
25+
# than one source or sink
26+
if len(sources) > 1 or len(sinks) > 1:
27+
maxInputFlow = 0
28+
for i in sources:
29+
maxInputFlow += sum(self.graph[i])
30+
31+
32+
size = len(self.graph) + 1
33+
for room in self.graph:
34+
room.insert(0, 0)
35+
self.graph.insert(0, [0] * size)
36+
for i in sources:
37+
self.graph[0][i + 1] = maxInputFlow
38+
self.sourceIndex = 0
39+
40+
size = len(self.graph) + 1
41+
for room in self.graph:
42+
room.append(0)
43+
self.graph.append([0] * size)
44+
for i in sinks:
45+
self.graph[i + 1][size - 1] = maxInputFlow
46+
self.sinkIndex = size - 1
47+
48+
49+
def findMaximumFlow(self):
50+
if self.maximumFlowAlgorithm is None:
51+
raise Exception("You need to set maximum flow algorithm before.")
52+
if self.sourceIndex is None or self.sinkIndex is None:
53+
return 0
54+
55+
self.maximumFlowAlgorithm.execute()
56+
return self.maximumFlowAlgorithm.getMaximumFlow()
57+
58+
def setMaximumFlowAlgorithm(self, Algorithm):
59+
self.maximumFlowAlgorithm = Algorithm(self)
60+
61+
62+
class FlowNetworkAlgorithmExecutor(object):
63+
def __init__(self, flowNetwork):
64+
self.flowNetwork = flowNetwork
65+
self.verticesCount = flowNetwork.verticesCount
66+
self.sourceIndex = flowNetwork.sourceIndex
67+
self.sinkIndex = flowNetwork.sinkIndex
68+
# it's just a reference, so you shouldn't change
69+
# it in your algorithms, use deep copy before doing that
70+
self.graph = flowNetwork.graph
71+
self.executed = False
72+
73+
def execute(self):
74+
if not self.executed:
75+
self._algorithm()
76+
self.executed = True
77+
78+
# You should override it
79+
def _algorithm(self):
80+
pass
81+
82+
83+
84+
class MaximumFlowAlgorithmExecutor(FlowNetworkAlgorithmExecutor):
85+
def __init__(self, flowNetwork):
86+
super(MaximumFlowAlgorithmExecutor, self).__init__(flowNetwork)
87+
# use this to save your result
88+
self.maximumFlow = -1
89+
90+
def getMaximumFlow(self):
91+
if not self.executed:
92+
raise Exception("You should execute algorithm before using its result!")
93+
94+
return self.maximumFlow
95+
96+
class PushRelabelExecutor(MaximumFlowAlgorithmExecutor):
97+
def __init__(self, flowNetwork):
98+
super(PushRelabelExecutor, self).__init__(flowNetwork)
99+
100+
self.preflow = [[0] * self.verticesCount for i in range(self.verticesCount)]
101+
102+
self.heights = [0] * self.verticesCount
103+
self.excesses = [0] * self.verticesCount
104+
105+
def _algorithm(self):
106+
self.heights[self.sourceIndex] = self.verticesCount
107+
108+
# push some substance to graph
109+
for nextVertexIndex, bandwidth in enumerate(self.graph[self.sourceIndex]):
110+
self.preflow[self.sourceIndex][nextVertexIndex] += bandwidth
111+
self.preflow[nextVertexIndex][self.sourceIndex] -= bandwidth
112+
self.excesses[nextVertexIndex] += bandwidth
113+
114+
# Relabel-to-front selection rule
115+
verticesList = [i for i in range(self.verticesCount)
116+
if i != self.sourceIndex and i != self.sinkIndex]
117+
118+
# move through list
119+
i = 0
120+
while i < len(verticesList):
121+
vertexIndex = verticesList[i]
122+
previousHeight = self.heights[vertexIndex]
123+
self.processVertex(vertexIndex)
124+
if self.heights[vertexIndex] > previousHeight:
125+
# if it was relabeled, swap elements
126+
# and start from 0 index
127+
verticesList.insert(0, verticesList.pop(i))
128+
i = 0
129+
else:
130+
i += 1
131+
132+
self.maximumFlow = sum(self.preflow[self.sourceIndex])
133+
134+
def processVertex(self, vertexIndex):
135+
while self.excesses[vertexIndex] > 0:
136+
for neighbourIndex in range(self.verticesCount):
137+
# if it's neighbour and current vertex is higher
138+
if self.graph[vertexIndex][neighbourIndex] - self.preflow[vertexIndex][neighbourIndex] > 0\
139+
and self.heights[vertexIndex] > self.heights[neighbourIndex]:
140+
self.push(vertexIndex, neighbourIndex)
141+
142+
self.relabel(vertexIndex)
143+
144+
def push(self, fromIndex, toIndex):
145+
preflowDelta = min(self.excesses[fromIndex],
146+
self.graph[fromIndex][toIndex] - self.preflow[fromIndex][toIndex])
147+
self.preflow[fromIndex][toIndex] += preflowDelta
148+
self.preflow[toIndex][fromIndex] -= preflowDelta
149+
self.excesses[fromIndex] -= preflowDelta
150+
self.excesses[toIndex] += preflowDelta
151+
152+
def relabel(self, vertexIndex):
153+
minHeight = None
154+
for toIndex in range(self.verticesCount):
155+
if self.graph[vertexIndex][toIndex] - self.preflow[vertexIndex][toIndex] > 0:
156+
if minHeight is None or self.heights[toIndex] < minHeight:
157+
minHeight = self.heights[toIndex]
158+
159+
if minHeight is not None:
160+
self.heights[vertexIndex] = minHeight + 1
161+
162+
if __name__ == '__main__':
163+
entrances = [0]
164+
exits = [3]
165+
# graph = [
166+
# [0, 0, 4, 6, 0, 0],
167+
# [0, 0, 5, 2, 0, 0],
168+
# [0, 0, 0, 0, 4, 4],
169+
# [0, 0, 0, 0, 6, 6],
170+
# [0, 0, 0, 0, 0, 0],
171+
# [0, 0, 0, 0, 0, 0],
172+
# ]
173+
graph = [[0, 7, 0, 0], [0, 0, 6, 0], [0, 0, 0, 8], [9, 0, 0, 0]]
174+
175+
# prepare our network
176+
flowNetwork = FlowNetwork(graph, entrances, exits)
177+
# set algorithm
178+
flowNetwork.setMaximumFlowAlgorithm(PushRelabelExecutor)
179+
# and calculate
180+
maximumFlow = flowNetwork.findMaximumFlow()
181+
182+
print("maximum flow is {}".format(maximumFlow))

0 commit comments

Comments
 (0)