-
Notifications
You must be signed in to change notification settings - Fork 1
/
relabel_to_front.py
125 lines (98 loc) · 4.13 KB
/
relabel_to_front.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
from flow_network import FlowNetwork
from linked_list import LinkedList
class RelabelToFront:
"""
Relabel-To-Front data structure.
"""
def __init__(self, network, source, sink):
"""
Generates a relabel-to-front data structure to
compute mas-flows.
"""
self.network = network
self.source = source
self.sink = sink
self.excess = {}
self.height = {}
self.current = {}
def initializePreflow(self):
"""Initializes a pre-flow that will evolve into a
max-flow during the execution of the algorithm.
Sets the source at the highest level and pushes
flow in a greedy way, completely saturating its
leaving edge capacities.
"""
for vertex in self.network.vertices():
self.excess[vertex] = 0
self.height[vertex] = 0
for edge in self.network.edges():
self.network.setFlow(edge, 0)
self.height[self.source] = len(self.network.vertices())
for vertex in self.network.neighbors(self.source):
edge = (self.source, vertex)
capacity = self.network.getCapacity(edge)
self.network.setFlow(edge, capacity)
self.excess[self.source] -= capacity
self.excess[vertex] = capacity
def push(self, fromVertex, toVertex):
"""
pushes as much excess flow as possible through the edge
(fromVertex, toVertex).
"""
edge = (fromVertex, toVertex)
deltaFlow = min(self.excess[fromVertex],
self.network.getResidualCapacity(edge))
self.network.increaseFlow(edge, deltaFlow)
self.excess[fromVertex] -= deltaFlow
self.excess[toVertex] += deltaFlow
def relabel(self, vertex):
"""
Relabels an overflowing vertex with the proper height so that
it can push part of its excess flow to one of its residual
neighbors at subsequent steps.
"""
self.height[vertex] = 1 + min(self.height[v] for v in self.network.residualNeighbors(vertex))
def canPush(self, fromVertex, toVertex):
"""
Checks whether an edge is suitable to push flow.
"""
edge = (fromVertex, toVertex)
return self.network.getResidualCapacity(edge) > 0 \
and self.height[fromVertex] == self.height[toVertex] + 1
def discharge(self, fromVertex):
"""
Discharges an overflowing vertex completely, iterating over its
residual neighbors, pushing flow and relabeling as appropriate.
"""
while self.excess[fromVertex] > 0:
if self.current[fromVertex] < len(self.network.adjacent[fromVertex]):
toVertex = self.network.adjacent[fromVertex][self.current[fromVertex]]
if self.canPush(fromVertex, toVertex):
self.push(fromVertex, toVertex)
else:
self.current[fromVertex] += 1
else:
self.relabel(fromVertex)
self.current[fromVertex] = 0
def maxFlow(self):
"""
Computes a max-flow across the network. Initializes a pre-flow,
maximally overcharging the vertices directly reachable from the
source, and maintains a queue to ensure that the vertices are
processed in the correct order, completely discharging an over-
flowing vertex at each step.
"""
self.initializePreflow()
vertices = LinkedList()
for vertex in self.network.vertices():
if vertex != self.source and vertex != self.sink:
vertices.add(vertex)
self.current[vertex] = 0
vertex = vertices.head
while vertex != None:
prevHeight = self.height[vertex.value]
self.discharge(vertex.value)
if self.height[vertex.value] > prevHeight:
vertices.moveToFront(vertex)
vertex = vertex.next
return self.network.getFlowAcrossVertex(self.source)