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