Open
Graph Drawing
Framework

 v. 2023.09 (Elderberry)
 

MaxFlowGoldbergTarjan.h
Go to the documentation of this file.
1 
33 #pragma once
34 
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 
44 // world666 is much better without OGDF_GT_USE_PUSH_RELABEL_SECOND_STAGE
45 
46 namespace ogdf {
47 
49 
52 template<typename TCap>
53 class MaxFlowGoldbergTarjan : public MaxFlowModule<TCap> {
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 
68 
69  inline TCap getCap(const edge e) const {
70  return e->target() == *this->m_s ? 0 : (*this->m_cap)[e];
71  }
72 
73  inline bool isResidualEdge(const adjEntry adj) const {
74  const edge e = adj->theEdge();
75  if (adj->theNode() == e->source()) {
76  return this->m_et->less((*this->m_flow)[e], getCap(e));
77  }
78  return this->m_et->greater((*this->m_flow)[e], (TCap)0);
79  }
80 
81  inline bool isAdmissible(const adjEntry adj) const {
82  OGDF_ASSERT(adj);
83  return isResidualEdge(adj) && m_label[adj->theNode()] == m_label[adj->twinNode()] + 1;
84  }
85 
86  inline bool isActive(const node v) const {
87  OGDF_ASSERT((v != *this->m_s && v != *this->m_t)
88  || (m_label[*this->m_s] == this->m_G->numberOfNodes() && m_label[*this->m_t] == 0));
89  return this->m_et->greater(m_ex[v], (TCap)0) && this->m_G->numberOfNodes() > m_label[v]
90  && m_label[v] > 0;
91  }
92 
93 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
94  inline void setActive(const node v) {
95  const int label = m_label[v];
96  OGDF_ASSERT(0 < label);
97  OGDF_ASSERT(label < this->m_G->numberOfNodes());
99  m_activeLabelListPosition[v] = m_activeLabelList[label].pushBack(v);
100  if (label > m_maxLabel) {
101  m_maxLabel = label;
102  }
103  }
104 
105  inline void findNewMaxLabel() {
106  while (m_maxLabel > 0 && m_activeLabelList[m_maxLabel].empty()) {
107  --m_maxLabel;
108  }
109  }
110 
111  inline void setInactive(const node v) {
114  m_activeLabelListPosition[v] = nullptr;
115  findNewMaxLabel();
116  }
117 #endif
118 
119  // sets label of v, maintaining m_labelList (moves node v to the correct list in the array)
120  inline void setLabel(const node v, int label) {
121 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
122  if (m_labelListPosition[v].valid()) {
123  m_labelList[m_label[v]].del(
124  m_labelListPosition[v]); // delete node from old list using noted position
125  }
126  m_labelListPosition[v] =
127  m_labelList[label].pushBack(v); // push node to new list and update iterator
128 #endif
129 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
130  if (m_activeLabelListPosition[v].valid()) {
131  OGDF_ASSERT(0 < m_label[v]);
132  OGDF_ASSERT(m_label[v] < this->m_G->numberOfNodes());
133  setInactive(v);
134  }
135  m_label[v] = label; // update label
136  if (v != *this->m_s && v != *this->m_t && isActive(v)) {
137  setActive(v);
138  }
139 #else
140  m_label[v] = label; // update label
141 #endif
142  }
143 
144 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
145  void gapRelabel() {
146 # ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
147  // XXX: this is a test but it seems to work and it seems to be fast!
148  const int n = m_maxLabel + 1;
149 # else
150  const int n = this->m_G->numberOfNodes();
151 # endif
152  for (int i = 1; i < n - 1; ++i) {
153  if (m_labelList[i].empty()) {
154  for (int j = i + 1; j < n; ++j) {
155  while (!m_labelList[j].empty()) {
156  setLabel(m_labelList[j].front(), this->m_G->numberOfNodes());
157  }
158  }
159  break;
160  }
161  }
162  }
163 #endif
164 
165  void push(const adjEntry adj) {
166  const edge e = adj->theEdge();
167  const node v = adj->theNode();
168  if (v == e->source()) {
169  const TCap value = min(m_ex[v], getCap(e) - (*this->m_flow)[e]);
170  OGDF_ASSERT(this->m_et->geq(value, (TCap)0));
171  (*this->m_flow)[e] += value;
172  m_ex[v] -= value;
173  m_ex[adj->twinNode()] += value;
174  } else {
175  const TCap value = min(m_ex[v], (*this->m_flow)[adj]);
176  OGDF_ASSERT(this->m_et->geq(value, (TCap)0));
177  (*this->m_flow)[adj] -= value;
178  m_ex[v] -= value;
179  m_ex[adj->twinNode()] += value;
180  }
181  }
182 
183  void globalRelabel() {
184  // breadth-first search to relabel nodes with their respective distance to the sink in the residual graph
185  const int n = this->m_G->numberOfNodes();
186  NodeArray<int> dist(*this->m_G, n); // distance array
187  List<node> queue; // reachable, not processed nodes
188  dist[*this->m_t] = 0;
189  queue.pushBack(*this->m_t);
190  while (!queue.empty()) { // is there a node to check?
191  node w = queue.popFrontRet();
192  for (adjEntry adj : w->adjEntries) {
193  node x = adj->twinNode();
194  if (isResidualEdge(adj->twin()) && dist[x] == n) { // not already seen
195  dist[x] = dist[w] + 1; // set distance of node to sink
196  queue.pushBack(x);
197  }
198  }
199  }
200  // set distance of unreachable nodes to "number of nodes" thus making them inactive
201  for (node w : this->m_G->nodes) {
202  setLabel(w, dist[w]);
203  }
204  }
205 
206  void relabel(const node v) {
207  int minLabel = this->m_G->numberOfNodes() - 1;
208  for (adjEntry adj : v->adjEntries) {
209  if (isResidualEdge(adj)) {
210  const int label = m_label[adj->twinNode()];
211  if (label < minLabel) {
212  minLabel = label;
213  }
214  }
215  }
216  if (minLabel + 1 != m_label[v]) { // == can happen after global relabel
217  setLabel(v, minLabel + 1);
218  }
219  }
220 
221  void relabelStage2(const node v) {
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  OGDF_ASSERT(minLabel + 1 != m_label[v]);
232  m_label[v] = minLabel + 1;
233  }
234 
235 public:
236  // first stage: push excess towards sink
237  TCap computeValue(const EdgeArray<TCap>& cap, const node& s, const node& t) {
238  // TODO: init this stuff in the module?
239  this->m_s = &s;
240  this->m_t = &t;
241  this->m_cap = &cap;
242  this->m_flow->init(*this->m_G, (TCap)0);
244 
245  m_label.init(*this->m_G);
246  m_ex.init(*this->m_G, 0);
247 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
248  m_activeLabelListPosition.init(*this->m_G, nullptr);
249  m_activeLabelList.init(1, this->m_G->numberOfNodes() - 1);
250  m_maxLabel = 0;
251 #endif
252 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
253  m_labelListPosition.init(*this->m_G, nullptr);
254  m_labelList.init(this->m_G->numberOfNodes() + 1);
255 #endif
256  m_cutNodes.clear();
257 
258  // initialize residual graph for first preflow
259  for (edge e : this->m_G->edges) {
260  if (e->source() == *this->m_s && e->target() != *this->m_s) { // ignore loops
261  (*this->m_flow)[e] = getCap(e);
262  m_ex[e->target()] += getCap(e); // "+" needed for the case of multigraphs
263  }
264  }
265 
266  if (*this->m_t == *this->m_s) {
267  return (TCap)0;
268  }
269 
270  NodeArray<adjEntry> curr(*this->m_G);
271  for (node v = this->m_G->firstNode(); v; v = v->succ()) {
272  curr[v] = v->firstAdj();
273  }
274 
275  globalRelabel(); // initialize distance labels
276 
277  int relCount = 0; // counts the relabel operations for the global relabeling heuristic
278 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
279  while (m_maxLabel != 0) {
281  const node v = m_activeLabelList[m_maxLabel].front();
284 #else
285  List<node> active;
286  for (adjEntry adj : (*this->m_s)->adjEntries) {
287  node w = adj->theEdge()->target();
288  if (w != *this->m_s) {
289  active.pushBack(w);
290  }
291  }
292  while (!active.empty()) {
293  const node v = active.front();
294 #endif
295  adjEntry& adj = curr[v];
296  if (v == *this->m_s || v == *this->m_t || !isActive(v)) {
297  // source, sink or not active: remove activity status
298 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
299  setInactive(v);
300 #else
301  active.popFront();
302 #endif
303  } else {
304  while (this->m_et->greater(m_ex[v], (TCap)0)) {
305  if (isAdmissible(adj)) {
306  // push and adjacent node becomes active
307 #ifdef OGDF_GT_USE_MAX_ACTIVE_LABEL
308  const node w = adj->twinNode();
309  if (w != *this->m_s && w != *this->m_t && !isActive(w)) {
310  // w will become active after push
311  setActive(w);
312  }
313  push(adj);
314  if (v != *this->m_s && !isActive(v)) {
315  setInactive(v);
316  }
317 #else
318  push(adj);
319  active.pushBack(adj->twinNode());
320 #endif
321  } else {
322  if (adj != v->lastAdj()) {
323  adj = adj->succ();
324  } else { // end of adjacency list
325  adj = v->firstAdj();
326  relabel(v);
327  ++relCount;
328 #ifdef OGDF_GT_USE_GAP_RELABEL_HEURISTIC
329  // only gapRelabel if we do not do a globalRelabel directly afterwards
330  if (relCount != this->m_G->numberOfNodes()
331 # if (OGDF_GT_GRH_STEPS > 1)
332  && relCount % OGDF_GT_GRH_STEPS
333  == 0 // obey frequency of gap relabel heuristic
334 # endif
335  ) {
336  gapRelabel();
337  }
338 #endif
339  break;
340  }
341  }
342  }
343  if (relCount == this->m_G->numberOfNodes()) {
344  relCount = 0;
345  globalRelabel();
346  }
347  }
348  }
349 
350  TCap result = 0;
351  for (adjEntry adj : (*this->m_t)->adjEntries) {
352  edge e = adj->theEdge();
353  if (e->target() == *this->m_t) {
354  result += (*this->m_flow)[e];
355  } else {
356  result -= (*this->m_flow)[e];
357  }
358  }
359  return result;
360  }
361 
362  // second stage: push excess that has not reached the sink back towards source
364  List<node> active;
365 #ifdef OGDF_GT_USE_PUSH_RELABEL_SECOND_STAGE
366  NodeArray<adjEntry> curr(*this->m_G);
367  for (node v = this->m_G->firstNode(); v; v = v->succ()) {
368  curr[v] = v->firstAdj();
369  m_label[v] = 1;
370  if (this->m_et->greater(m_ex[v], (TCap)0) && v != *this->m_s && v != *this->m_t) {
371  active.pushBack(v);
372  }
373  }
374  if (active.empty()) {
375  return;
376  }
377 
378  m_label[*this->m_s] = 0;
379  while (!active.empty()) {
380  node v = active.front();
381  if (v == *this->m_s || v == *this->m_t || !isActive(v)) {
382  active.popFront();
383  } else {
384  adjEntry& adj = curr[v];
385  if (isAdmissible(adj)) {
386  push(adj);
387  active.pushBack(adj->twinNode());
388  } else {
389  if (adj == v->lastAdj()) {
390  // no admissible outgoing edge found -> relabel node!
391  relabelStage2(v);
392  adj = v->firstAdj();
393 # if 0
394  // node is still active but move it to the end of the queue
395  // (don't know if this is really necessary)
396  active.popFront();
397  active.pushBack(v);
398 # endif
399  } else {
400  adj = adj->succ();
401  }
402  }
403  }
404  }
405 #else // USE_PUSH_RELABEL_SECOND_STAGE
406  m_ex[*this->m_s] = m_ex[*this->m_t] = 0;
407  for (node v = this->m_G->firstNode(); v; v = v->succ()) {
408  if (this->m_et->greater(m_ex[v], (TCap)0)) {
409  active.pushBack(v);
410  }
411  }
412  while (!active.empty()) {
413  const node v = active.popFrontRet();
414  if (this->m_et->greater(m_ex[v], (TCap)0) && v != *this->m_s && v != *this->m_t) {
415  for (adjEntry adj = v->firstAdj(); adj; adj = adj->succ()) {
416  const edge e = adj->theEdge();
417  const node u = e->source();
418  if (u != v) { // e is incoming edge
419  if (this->m_et->greater(m_ex[v], (TCap)0) && isResidualEdge(adj)) {
420  push(adj);
421  if (u != *this->m_s) {
422  active.pushFront(u);
423  }
424  }
425  }
426  }
427  }
428  }
429 #endif // USE_PUSH_RELABEL_SECOND_STAGE
430  }
431 
437 };
438 
439 }
ogdf
The namespace for all OGDF objects.
Definition: AugmentationModule.h:36
ogdf::MaxFlowGoldbergTarjan::relabel
void relabel(const node v)
Definition: MaxFlowGoldbergTarjan.h:206
ogdf::MaxFlowModule< TCap >::isFeasibleInstance
bool isFeasibleInstance() const
Return whether the instance is feasible, i.e. the capacities are non-negative.
Definition: MaxFlowModule.h:147
OGDF_ASSERT
#define OGDF_ASSERT(expr)
Assert condition expr. See doc/build.md for more information.
Definition: basic.h:54
MaxFlowModule.h
Interface for Max Flow Algorithms.
ogdf::AdjElement::theNode
node theNode() const
Returns the node whose adjacency list contains this element.
Definition: Graph_d.h:159
ogdf::List::popFront
void popFront()
Removes the first element from the list.
Definition: List.h:1575
ogdf::MaxFlowModule< TCap >::m_t
const node * m_t
Pointer to the sink node.
Definition: MaxFlowModule.h:47
ogdf::MaxFlowGoldbergTarjan::m_cutEdges
List< edge > m_cutEdges
Definition: MaxFlowGoldbergTarjan.h:67
ogdf::begin
HypergraphRegistry< HypernodeElement >::iterator begin(const HypergraphRegistry< HypernodeElement > &self)
ogdf::NodeElement::lastAdj
adjEntry lastAdj() const
Returns the last entry in the adjacency list.
Definition: Graph_d.h:282
ogdf::MaxFlowGoldbergTarjan::m_label
NodeArray< int > m_label
Definition: MaxFlowGoldbergTarjan.h:54
ogdf::MaxFlowGoldbergTarjan::getCap
TCap getCap(const edge e) const
Definition: MaxFlowGoldbergTarjan.h:69
ogdf::List::popFrontRet
E popFrontRet()
Removes the first element from the list and returns it.
Definition: List.h:1581
ogdf::MaxFlowGoldbergTarjan::isActive
bool isActive(const node v) const
Definition: MaxFlowGoldbergTarjan.h:86
ogdf::MaxFlowGoldbergTarjan
Computes a max flow via Preflow-Push (global relabeling and gap relabeling heuristic).
Definition: MaxFlowGoldbergTarjan.h:53
ogdf::Array::init
void init()
Reinitializes the array to an array with empty index set.
Definition: Array.h:367
ogdf::MaxFlowGoldbergTarjan::globalRelabel
void globalRelabel()
Definition: MaxFlowGoldbergTarjan.h:183
ogdf::AdjElement::twin
adjEntry twin() const
Returns the corresponding adjacency element associated with the same edge.
Definition: Graph_d.h:165
ogdf::AdjElement
Class for adjacency list elements.
Definition: Graph_d.h:135
ogdf::EpsilonTest::less
std::enable_if< std::is_integral< T >::value, bool >::type less(const T &x, const T &y) const
Compare if x is LESS than y for integral types.
Definition: EpsilonTest.h:57
ogdf::MaxFlowGoldbergTarjan::m_ex
NodeArray< TCap > m_ex
Definition: MaxFlowGoldbergTarjan.h:55
ogdf::MaxFlowModule< TCap >::m_et
EpsilonTest * m_et
Pointer to the used EpsilonTest.
Definition: MaxFlowModule.h:42
ogdf::MaxFlowGoldbergTarjan::computeFlowAfterValue
void computeFlowAfterValue()
Compute the flow itself after the flow value is already computed. Only used in algorithms with 2 phas...
Definition: MaxFlowGoldbergTarjan.h:363
ogdf::AdjElement::theEdge
edge theEdge() const
Returns the edge associated with this adjacency entry.
Definition: Graph_d.h:153
ogdf::MaxFlowModule< TCap >::m_s
const node * m_s
Pointer to the source node.
Definition: MaxFlowModule.h:46
ogdf::Graph::nodes
internal::GraphObjectContainer< NodeElement > nodes
The container containing all node objects.
Definition: Graph_d.h:924
ogdf::MaxFlowModule< TCap >::m_G
const Graph * m_G
Pointer to the given graph.
Definition: MaxFlowModule.h:44
ogdf::MaxFlowGoldbergTarjan::isAdmissible
bool isAdmissible(const adjEntry adj) const
Definition: MaxFlowGoldbergTarjan.h:81
ogdf::MaxFlowGoldbergTarjan::findNewMaxLabel
void findNewMaxLabel()
Definition: MaxFlowGoldbergTarjan.h:105
ogdf::List::pushFront
iterator pushFront(const E &x)
Adds element x at the beginning of the list.
Definition: List.h:1524
ogdf::MaxFlowGoldbergTarjan::push
void push(const adjEntry adj)
Definition: MaxFlowGoldbergTarjan.h:165
ogdf::Graph::numberOfNodes
int numberOfNodes() const
Returns the number of nodes in the graph.
Definition: Graph_d.h:974
ogdf::MaxFlowGoldbergTarjan::setInactive
void setInactive(const node v)
Definition: MaxFlowGoldbergTarjan.h:111
ogdf::Array
The parameterized class Array implements dynamic arrays of type E.
Definition: Array.h:214
ogdf::AdjElement::succ
adjEntry succ() const
Returns the successor in the adjacency list.
Definition: Graph_d.h:211
ogdf::NodeElement::adjEntries
internal::GraphObjectContainer< AdjElement > adjEntries
The container containing all entries in the adjacency list of this node.
Definition: Graph_d.h:264
ogdf::MaxFlowGoldbergTarjan::isResidualEdge
bool isResidualEdge(const adjEntry adj) const
Definition: MaxFlowGoldbergTarjan.h:73
ogdf::Graph::firstNode
node firstNode() const
Returns the first node in the list of all nodes.
Definition: Graph_d.h:989
ogdf::MaxFlowGoldbergTarjan::m_activeLabelList
Array< List< node > > m_activeLabelList
Definition: MaxFlowGoldbergTarjan.h:58
ogdf::EdgeElement::source
node source() const
Returns the source node of the edge.
Definition: Graph_d.h:391
ogdf::List
Doubly linked lists (maintaining the length of the list).
Definition: List.h:42
ogdf::internal::GraphRegisteredArray
RegisteredArray for nodes, edges and adjEntries of a graph.
Definition: Graph_d.h:651
ogdf::EpsilonTest::greater
std::enable_if< std::is_integral< T >::value, bool >::type greater(const T &x, const T &y) const
Compare if x is GREATER than y for integral types.
Definition: EpsilonTest.h:161
ogdf::MaxFlowGoldbergTarjan::setLabel
void setLabel(const node v, int label)
Definition: MaxFlowGoldbergTarjan.h:120
ogdf::AdjElement::twinNode
node twinNode() const
Returns the associated node of the corresponding adjacency entry (shorthand for twin()->theNode()).
Definition: Graph_d.h:168
ogdf::MaxFlowGoldbergTarjan::relabelStage2
void relabelStage2(const node v)
Definition: MaxFlowGoldbergTarjan.h:221
ogdf::Graph::edges
internal::GraphObjectContainer< EdgeElement > edges
The container containing all edge objects.
Definition: Graph_d.h:927
ogdf::MaxFlowModule
Definition: MaxFlowModule.h:40
ogdf::NodeElement::firstAdj
adjEntry firstAdj() const
Returns the first entry in the adjaceny list.
Definition: Graph_d.h:279
ogdf::NodeElement::succ
node succ() const
Returns the successor in the list of all nodes.
Definition: Graph_d.h:285
ogdf::EdgeElement
Class for the representation of edges.
Definition: Graph_d.h:356
ogdf::MaxFlowGoldbergTarjan::m_activeLabelListPosition
NodeArray< ListIterator< node > > m_activeLabelListPosition
Definition: MaxFlowGoldbergTarjan.h:57
ogdf::MaxFlowGoldbergTarjan::m_cutNodes
List< node > m_cutNodes
Definition: MaxFlowGoldbergTarjan.h:66
ogdf::MaxFlowGoldbergTarjan::setActive
void setActive(const node v)
Definition: MaxFlowGoldbergTarjan.h:94
ogdf::MaxFlowGoldbergTarjan::m_maxLabel
int m_maxLabel
Definition: MaxFlowGoldbergTarjan.h:59
ogdf::RegisteredArray< GraphRegistry< Key >, Value, WithDefault, Graph >::init
void init(const Graph *base=nullptr)
Reinitializes the array. Associates the array with the matching registry of base.
Definition: RegisteredArray.h:849
ogdf::MaxFlowModule< TCap >::m_cap
const EdgeArray< TCap > * m_cap
Pointer to the given capacity array.
Definition: MaxFlowModule.h:45
ogdf::MaxFlowGoldbergTarjan::computeValue
TCap computeValue(const EdgeArray< TCap > &cap, const node &s, const node &t)
Compute only the value of the flow.
Definition: MaxFlowGoldbergTarjan.h:237
ogdf::EpsilonTest::geq
std::enable_if< std::is_integral< T >::value, bool >::type geq(const T &x, const T &y) const
Compare if x is GEQ to y for integral types.
Definition: EpsilonTest.h:135
ogdf::EdgeElement::target
node target() const
Returns the target node of the edge.
Definition: Graph_d.h:394
ogdf::NodeElement
Class for the representation of nodes.
Definition: Graph_d.h:233
ogdf::MaxFlowModule< TCap >::m_flow
EdgeArray< TCap > * m_flow
Pointer to (extern) flow array.
Definition: MaxFlowModule.h:43
ogdf::List::pushBack
iterator pushBack(const E &x)
Adds element x at the end of the list.
Definition: List.h:1537
ogdf::internal::EdgeArrayBase2
RegisteredArray for edges of a graph, specialized for EdgeArray<edge>.
Definition: Graph_d.h:709
ogdf::List::clear
void clear()
Removes all elements from the list.
Definition: List.h:1616