1 /** \file
2  * \brief Declaration and implementation of Goldberg-Tarjan max-flow algorithm
3  *        with global relabeling and gap relabeling heuristic
4  *
5  * \author Stephan Beyer, Hennes Hoffmann, Tilo Wiedera
6  *
7  * \par License:
8  * This file is part of the Open Graph Drawing Framework (OGDF).
9  *
10  * \par
11  * Copyright (C)<br>
12  * See README.md in the OGDF root directory for details.
13  *
14  * \par
15  * This program is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU General Public License
17  * Version 2 or 3 as published by the Free Software Foundation;
18  * see the file LICENSE.txt included in the packaging of this file
19  * for details.
20  *
21  * \par
22  * This program is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
25  * GNU General Public License for more details.
26  *
27  * \par
28  * You should have received a copy of the GNU General Public
29  * License along with this program; if not, see
30  * http://www.gnu.org/copyleft/gpl.html
31  */
32 
33 #pragma once
34 
35 #include <ogdf/graphalg/MaxFlowModule.h>
36 
37 //#define OGDF_GT_USE_GAP_RELABEL_HEURISTIC
38 #define OGDF_GT_USE_MAX_ACTIVE_LABEL
39 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
40 //#define OGDF_GT_GRH_STEPS	1	// gap relabel frequency: call gapRelabel() after OGDF_GT_GRH_STEPS relabel() operations (1 == off)
41 #endif
42 #define OGDF_GT_USE_PUSH_RELABEL_SECOND_STAGE
43 // world666 is much better without OGDF_GT_USE_PUSH_RELABEL_SECOND_STAGE
44 
45 namespace ogdf {
46 
47 //! Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
48 /**
49  * @ingroup ga-flow
50  */
51 template<typename TCap>
52 class MaxFlowGoldbergTarjan : public MaxFlowModule<TCap>
53 {
54 	NodeArray<int> m_label;
55 	NodeArray<TCap> m_ex; // ex_f(v) values will be saved here to save runtime
56 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
57 	NodeArray< ListIterator<node> > m_activeLabelListPosition; // holds the iterator of every active node in the corresp. list of m_labeList
58 	Array< List<node> > m_activeLabelList; // array indexed by label, contains list of active nodes with that label
59 	int m_maxLabel = 0; // the maximum label among all active nodes
60 #endif
61 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
62 	NodeArray< ListIterator<node> > m_labelListPosition; // holds the iterator of every node in the corresp. list of m_labeList
63 	Array< List<node> > m_labelList; // array indexed by label, contains list of nodes with that label
64 #endif
65 
66 	mutable List<node> m_cutNodes;
67 	mutable List<edge> m_cutEdges;
68 
getCap(const edge e)69 	inline TCap getCap(const edge e) const {
70 		return e->target() == *this->m_s ? 0 : (*this->m_cap)[e];
71 	}
72 
isResidualEdge(const adjEntry adj)73 	inline bool isResidualEdge(const adjEntry adj) const
74 	{
75 		const edge e = adj->theEdge();
76 		if (adj->theNode() == e->source()) {
77 			return this->m_et->less((*this->m_flow)[e], getCap(e));
78 		}
79 		return this->m_et->greater((*this->m_flow)[e], (TCap) 0);
80 	}
81 
isAdmissible(const adjEntry adj)82 	inline bool isAdmissible(const adjEntry adj) const
83 	{
84 		OGDF_ASSERT(adj);
85 		return isResidualEdge(adj)
86 		    && m_label[adj->theNode()] == m_label[adj->twinNode()] + 1;
87 	}
88 
isActive(const node v)89 	inline bool isActive(const node v) const
90 	{
91 		OGDF_ASSERT((v != *this->m_s && v != *this->m_t)
92 		  || (m_label[*this->m_s] == this->m_G->numberOfNodes() && m_label[*this->m_t] == 0));
93 		return this->m_et->greater(m_ex[v], (TCap) 0)
94 		    && this->m_G->numberOfNodes() > m_label[v]
95 		    && m_label[v] > 0;
96 	}
97 
98 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
setActive(const node v)99 	inline void setActive(const node v)
100 	{
101 		const int label = m_label[v];
102 		OGDF_ASSERT(0 < label);
103 		OGDF_ASSERT(label < this->m_G->numberOfNodes());
104 		OGDF_ASSERT(!m_activeLabelListPosition[v].valid());
105 		m_activeLabelListPosition[v] = m_activeLabelList[label].pushBack(v);
106 		if (label > m_maxLabel) {
107 			m_maxLabel = label;
108 		}
109 	}
110 
findNewMaxLabel()111 	inline void findNewMaxLabel()
112 	{
113 		while (m_maxLabel > 0
114 		    && m_activeLabelList[m_maxLabel].empty()) {
115 			--m_maxLabel;
116 		}
117 	}
118 
setInactive(const node v)119 	inline void setInactive(const node v)
120 	{
121 		OGDF_ASSERT(m_activeLabelListPosition[v].valid());
122 		m_activeLabelList[m_label[v]].del(m_activeLabelListPosition[v]);
123 		m_activeLabelListPosition[v] = nullptr;
124 		findNewMaxLabel();
125 	}
126 #endif
127 
128 	// sets label of v, maintaining m_labelList (moves node v to the correct list in the array)
setLabel(const node v,int label)129 	inline void setLabel(const node v, int label)
130 	{
131 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
132 		if (m_labelListPosition[v].valid()) {
133 			m_labelList[m_label[v]].del(m_labelListPosition[v]); // delete node from old list using noted position
134 		}
135 		m_labelListPosition[v] = m_labelList[label].pushBack(v); // push node to new list and update iterator
136 #endif
137 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
138 		if (m_activeLabelListPosition[v].valid()) {
139 			OGDF_ASSERT(0 < m_label[v]);
140 			OGDF_ASSERT(m_label[v] < this->m_G->numberOfNodes());
141 			setInactive(v);
142 		}
143 		m_label[v] = label; // update label
144 		if (v != *this->m_s
145 		 && v != *this->m_t
146 		 && isActive(v)) {
147 			setActive(v);
148 		}
149 #else
150 		m_label[v] = label; // update label
151 #endif
152 	}
153 
154 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
gapRelabel()155 	void gapRelabel()
156 	{
157 #  ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
158 		// XXX: this is a test but it seems to work and it seems to be fast!
159 		const int n = m_maxLabel + 1;
160 #  else
161 		const int n = this->m_G->numberOfNodes();
162 #  endif
163 		for (int i = 1; i < n - 1; ++i) {
164 			if (m_labelList[i].empty()) {
165 				for (int j = i + 1; j < n; ++j) {
166 					while (!m_labelList[j].empty()) {
167 						setLabel(m_labelList[j].front(), this->m_G->numberOfNodes());
168 					}
169 				}
170 				break;
171 			}
172 		}
173 	}
174 #endif
175 
push(const adjEntry adj)176 	void push(const adjEntry adj)
177 	{
178 		const edge e = adj->theEdge();
179 		const node v = adj->theNode();
180 		if (v == e->source()) {
181 			const TCap value = min(m_ex[v], getCap(e) - (*this->m_flow)[e]);
182 			OGDF_ASSERT(this->m_et->geq(value, (TCap) 0));
183 			(*this->m_flow)[e] += value;
184 			m_ex[v] -= value;
185 			m_ex[adj->twinNode()] += value;
186 		} else {
187 			const TCap value = min(m_ex[v], (*this->m_flow)[adj]);
188 			OGDF_ASSERT(this->m_et->geq(value, (TCap) 0));
189 			(*this->m_flow)[adj] -= value;
190 			m_ex[v] -= value;
191 			m_ex[adj->twinNode()] += value;
192 		}
193 	}
194 
globalRelabel()195 	void globalRelabel()
196 	{
197 		// breadth-first search to relabel nodes with their respective distance to the sink in the residual graph
198 		const int n = this->m_G->numberOfNodes();
199 		NodeArray<int> dist(*this->m_G, n); // distance array
200 		List<node> queue; // reachable, not processed nodes
201 		dist[*this->m_t] = 0;
202 		queue.pushBack(*this->m_t);
203 		while (!queue.empty()) { // is there a node to check?
204 			node w = queue.popFrontRet();
205 			for(adjEntry adj : w->adjEntries) {
206 				node x = adj->twinNode();
207 				if (isResidualEdge(adj->twin())
208 				 && dist[x] == n) { // not already seen
209 					dist[x] = dist[w] + 1; // set distance of node to sink
210 					queue.pushBack(x);
211 				}
212 			}
213 		}
214 		// set distance of unreachable nodes to "number of nodes" thus making them inactive
215 		for(node w : this->m_G->nodes) {
216 			setLabel(w, dist[w]);
217 		}
218 	}
219 
relabel(const node v)220 	void relabel(const node v)
221 	{
222 		int minLabel = this->m_G->numberOfNodes() - 1;
223 		for(adjEntry adj : v->adjEntries) {
224 			if (isResidualEdge(adj)) {
225 				const int label = m_label[adj->twinNode()];
226 				if (label < minLabel) {
227 					minLabel = label;
228 				}
229 			}
230 		}
231 		if (minLabel + 1 != m_label[v]) { // == can happen after global relabel
232 			setLabel(v, minLabel + 1);
233 		}
234 	}
235 
relabelStage2(const node v)236 	void relabelStage2(const node v)
237 	{
238 		int minLabel = this->m_G->numberOfNodes() - 1;
239 		for(adjEntry adj : v->adjEntries) {
240 			if (isResidualEdge(adj)) {
241 				const int label = m_label[adj->twinNode()];
242 				if (label < minLabel) {
243 					minLabel = label;
244 				}
245 			}
246 		}
247 		OGDF_ASSERT(minLabel + 1 != m_label[v]);
248 		m_label[v] = minLabel + 1;
249 	}
250 
251 public:
252 	// first stage: push excess towards sink
computeValue(const EdgeArray<TCap> & cap,const node & s,const node & t)253 	TCap computeValue(const EdgeArray<TCap> &cap, const node &s, const node &t)
254 	{
255 		// TODO: init this stuff in the module?
256 		this->m_s = &s;
257 		this->m_t = &t;
258 		this->m_cap = &cap;
259 		this->m_flow->init(*this->m_G, (TCap) 0);
260 		OGDF_ASSERT(this->isFeasibleInstance());
261 
262 		m_label.init(*this->m_G);
263 		m_ex.init(*this->m_G, 0);
264 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
265 		m_activeLabelListPosition.init(*this->m_G, nullptr);
266 		m_activeLabelList.init(1, this->m_G->numberOfNodes() - 1);
267 		m_maxLabel = 0;
268 #endif
269 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
270 		m_labelListPosition.init(*this->m_G, nullptr);
271 		m_labelList.init(this->m_G->numberOfNodes() + 1);
272 #endif
273 		m_cutNodes.clear();
274 
275 		// initialize residual graph for first preflow
276 		for(edge e : this->m_G->edges) {
277 			if (e->source() == *this->m_s
278 			&& e->target() != *this->m_s) { // ignore loops
279 				(*this->m_flow)[e] = getCap(e);
280 				m_ex[e->target()] += getCap(e); // "+" needed for the case of multigraphs
281 			}
282 		}
283 
284 		if(*this->m_t == *this->m_s) {
285 			return (TCap) 0;
286 		}
287 
288 		NodeArray<adjEntry> curr(*this->m_G);
289 		for (node v = this->m_G->firstNode(); v; v = v->succ()) {
290 			curr[v] = v->firstAdj();
291 		}
292 
293 		globalRelabel(); // initialize distance labels
294 
295 		int relCount = 0; // counts the relabel operations for the global relabeling heuristic
296 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
297 		while (m_maxLabel != 0) {
298 			OGDF_ASSERT(!m_activeLabelList[m_maxLabel].empty());
299 			const node v = m_activeLabelList[m_maxLabel].front();
300 			OGDF_ASSERT(m_maxLabel == m_label[v]);
301 			OGDF_ASSERT(m_activeLabelListPosition[v] == m_activeLabelList[m_maxLabel].begin());
302 #else
303 		List<node> active;
304 		for(adjEntry adj : (*this->m_s)->adjEntries) {
305 			node w = adj->theEdge()->target();
306 			if (w != *this->m_s) {
307 				active.pushBack(w);
308 			}
309 		}
310 		while (!active.empty()) {
311 			const node v = active.front();
312 #endif
313 			adjEntry &adj = curr[v];
314 			if (v == *this->m_s
315 			 || v == *this->m_t
316 			 || !isActive(v)) {
317 				// source, sink or not active: remove activity status
318 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
319 				setInactive(v);
320 #else
321 				active.popFront();
322 #endif
323 			} else {
324 				while (this->m_et->greater(m_ex[v], (TCap) 0)) {
325 					if (isAdmissible(adj)) {
326 						// push and adjacent node becomes active
327 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
328 						const node w = adj->twinNode();
329 						if (w != *this->m_s
330 						 && w != *this->m_t
331 						 && !isActive(w)) {
332 							// w will become active after push
333 							setActive(w);
334 						}
335 						push(adj);
336 						if (v != *this->m_s
337 						 && !isActive(v)) {
338 							setInactive(v);
339 						}
340 #else
341 						push(adj);
342 						active.pushBack(adj->twinNode());
343 #endif
344 					} else {
345 						if (adj != v->lastAdj()) {
346 							adj = adj->succ();
347 						} else { // end of adjacency list
348 							adj = v->firstAdj();
349 							relabel(v);
350 							++relCount;
351 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
352 							// only gapRelabel if we do not do a globalRelabel directly afterwards
353 							if (relCount != this->m_G->numberOfNodes()
354 #  if (OGDF_GT_GRH_STEPS > 1)
355 							 && relCount % OGDF_GT_GRH_STEPS == 0 // obey frequency of gap relabel heuristic
356 #  endif
357 							  ) {
358 								gapRelabel();
359 							}
360 #endif
361 							break;
362 						}
363 					}
364 				}
365 				if (relCount == this->m_G->numberOfNodes()) {
366 					relCount = 0;
367 					globalRelabel();
368 				}
369 			}
370 		}
371 
372 		TCap result = 0;
373 		for(adjEntry adj : (*this->m_t)->adjEntries) {
374 			edge e = adj->theEdge();
375 			if(e->target() == *this->m_t) {
376 				result += (*this->m_flow)[e];
377 			} else {
378 				result -= (*this->m_flow)[e];
379 			}
380 		}
381 		return result;
382 	}
383 
384 	// second stage: push excess that has not reached the sink back towards source
385 	void computeFlowAfterValue()
386 	{
387 		List<node> active;
388 #ifdef OGDF_GT_USE_PUSH_RELABEL_SECOND_STAGE
389 		NodeArray<adjEntry> curr(*this->m_G);
390 		for (node v = this->m_G->firstNode(); v; v = v->succ()) {
391 			curr[v] = v->firstAdj();
392 			m_label[v] = 1;
393 			if (this->m_et->greater(m_ex[v], (TCap) 0) && v != *this->m_s && v != *this->m_t) {
394 				active.pushBack(v);
395 			}
396 		}
397 		if (active.empty()) {
398 			return;
399 		}
400 
401 		m_label[*this->m_s] = 0;
402 		while (!active.empty()) {
403 			node v = active.front();
404 			if (v == *this->m_s
405 			 || v == *this->m_t
406 			 || !isActive(v)) {
407 				active.popFront();
408 			} else {
409 				adjEntry &adj = curr[v];
410 				if (isAdmissible(adj)) {
411 					push(adj);
412 					active.pushBack(adj->twinNode());
413 				} else {
414 					if (adj == v->lastAdj()) {
415 						// no admissible outgoing edge found -> relabel node!
416 						relabelStage2(v);
417 						adj = v->firstAdj();
418 #if 0
419 						// node is still active but move it to the end of the queue
420 						// (don't know if this is really necessary)
421 						active.popFront();
422 						active.pushBack(v);
423 #endif
424 					} else {
425 						adj = adj->succ();
426 					}
427 				}
428 			}
429 		}
430 #else // USE_PUSH_RELABEL_SECOND_STAGE
431 		m_ex[*this->m_s] = m_ex[*this->m_t] = 0;
432 		for (node v = this->m_G->firstNode(); v; v = v->succ()) {
433 			if (this->m_et->greater(m_ex[v], (TCap) 0)) {
434 				active.pushBack(v);
435 			}
436 		}
437 		while (!active.empty()) {
438 			const node v = active.popFrontRet();
439 			if (this->m_et->greater(m_ex[v], (TCap) 0) && v != *this->m_s && v != *this->m_t) {
440 				for (adjEntry adj = v->firstAdj(); adj; adj = adj->succ()) {
441 					const edge e = adj->theEdge();
442 					const node u = e->source();
443 					if (u != v) { // e is incoming edge
444 						if (this->m_et->greater(m_ex[v], (TCap) 0)
445 						 && isResidualEdge(adj)) {
446 							push(adj);
447 							if (u != *this->m_s) {
448 								active.pushFront(u);
449 							}
450 						}
451 					}
452 				}
453 			}
454 		}
455 #endif // USE_PUSH_RELABEL_SECOND_STAGE
456 	}
457 	using MaxFlowModule<TCap>::useEpsilonTest;
458 	using MaxFlowModule<TCap>::init;
459 	using MaxFlowModule<TCap>::computeFlow;
460 	using MaxFlowModule<TCap>::computeFlowAfterValue;
461 	using MaxFlowModule<TCap>::MaxFlowModule;
462 };
463 
464 }
465