|
| 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