OR-Tools  9.1
max_flow.cc
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 #include "ortools/graph/max_flow.h"
15 
16 #include <algorithm>
17 #include <string>
18 
19 #include "absl/memory/memory.h"
20 #include "absl/strings/str_format.h"
21 #include "ortools/graph/graph.h"
22 #include "ortools/graph/graphs.h"
23 
24 namespace operations_research {
25 
26 SimpleMaxFlow::SimpleMaxFlow() : num_nodes_(0) {}
27 
30  const ArcIndex num_arcs = arc_tail_.size();
31  num_nodes_ = std::max(num_nodes_, tail + 1);
32  num_nodes_ = std::max(num_nodes_, head + 1);
33  arc_tail_.push_back(tail);
34  arc_head_.push_back(head);
35  arc_capacity_.push_back(capacity);
36  return num_arcs;
37 }
38 
39 NodeIndex SimpleMaxFlow::NumNodes() const { return num_nodes_; }
40 
41 ArcIndex SimpleMaxFlow::NumArcs() const { return arc_tail_.size(); }
42 
43 NodeIndex SimpleMaxFlow::Tail(ArcIndex arc) const { return arc_tail_[arc]; }
44 
45 NodeIndex SimpleMaxFlow::Head(ArcIndex arc) const { return arc_head_[arc]; }
46 
48  return arc_capacity_[arc];
49 }
50 
52  arc_capacity_[arc] = capacity;
53 }
54 
56  const ArcIndex num_arcs = arc_capacity_.size();
57  arc_flow_.assign(num_arcs, 0);
58  underlying_max_flow_.reset();
59  underlying_graph_.reset();
60  optimal_flow_ = 0;
61  if (source == sink || source < 0 || sink < 0) {
62  return BAD_INPUT;
63  }
64  if (source >= num_nodes_ || sink >= num_nodes_) {
65  return OPTIMAL;
66  }
67  underlying_graph_ = absl::make_unique<Graph>(num_nodes_, num_arcs);
68  underlying_graph_->AddNode(source);
69  underlying_graph_->AddNode(sink);
70  for (int arc = 0; arc < num_arcs; ++arc) {
71  underlying_graph_->AddArc(arc_tail_[arc], arc_head_[arc]);
72  }
73  underlying_graph_->Build(&arc_permutation_);
74  underlying_max_flow_ = absl::make_unique<GenericMaxFlow<Graph>>(
75  underlying_graph_.get(), source, sink);
76  for (ArcIndex arc = 0; arc < num_arcs; ++arc) {
77  ArcIndex permuted_arc =
78  arc < arc_permutation_.size() ? arc_permutation_[arc] : arc;
79  underlying_max_flow_->SetArcCapacity(permuted_arc, arc_capacity_[arc]);
80  }
81  if (underlying_max_flow_->Solve()) {
82  optimal_flow_ = underlying_max_flow_->GetOptimalFlow();
83  for (ArcIndex arc = 0; arc < num_arcs; ++arc) {
84  ArcIndex permuted_arc =
85  arc < arc_permutation_.size() ? arc_permutation_[arc] : arc;
86  arc_flow_[arc] = underlying_max_flow_->Flow(permuted_arc);
87  }
88  }
89  // Translate the GenericMaxFlow::Status. It is different because NOT_SOLVED
90  // does not make sense in the simple api.
91  switch (underlying_max_flow_->status()) {
93  return BAD_RESULT;
95  return OPTIMAL;
97  return POSSIBLE_OVERFLOW;
99  return BAD_INPUT;
101  return BAD_RESULT;
102  }
103  return BAD_RESULT;
104 }
105 
106 FlowQuantity SimpleMaxFlow::OptimalFlow() const { return optimal_flow_; }
107 
108 FlowQuantity SimpleMaxFlow::Flow(ArcIndex arc) const { return arc_flow_[arc]; }
109 
110 void SimpleMaxFlow::GetSourceSideMinCut(std::vector<NodeIndex>* result) {
111  if (underlying_max_flow_ == nullptr) return;
112  underlying_max_flow_->GetSourceSideMinCut(result);
113 }
114 
115 void SimpleMaxFlow::GetSinkSideMinCut(std::vector<NodeIndex>* result) {
116  if (underlying_max_flow_ == nullptr) return;
117  underlying_max_flow_->GetSinkSideMinCut(result);
118 }
119 
121  if (underlying_max_flow_ == nullptr) return FlowModel();
122  return underlying_max_flow_->CreateFlowModel();
123 }
124 
125 template <typename Graph>
127  NodeIndex sink)
128  : graph_(graph),
129  node_excess_(),
130  node_potential_(),
131  residual_arc_capacity_(),
132  first_admissible_arc_(),
133  active_nodes_(),
134  source_(source),
135  sink_(sink),
136  use_global_update_(true),
137  use_two_phase_algorithm_(true),
138  process_node_by_height_(true),
139  check_input_(true),
140  check_result_(true),
141  stats_("MaxFlow") {
142  SCOPED_TIME_STAT(&stats_);
143  DCHECK(graph->IsNodeValid(source));
144  DCHECK(graph->IsNodeValid(sink));
145  const NodeIndex max_num_nodes = Graphs<Graph>::NodeReservation(*graph_);
146  if (max_num_nodes > 0) {
147  node_excess_.Reserve(0, max_num_nodes - 1);
148  node_excess_.SetAll(0);
149  node_potential_.Reserve(0, max_num_nodes - 1);
150  node_potential_.SetAll(0);
151  first_admissible_arc_.Reserve(0, max_num_nodes - 1);
152  first_admissible_arc_.SetAll(Graph::kNilArc);
153  bfs_queue_.reserve(max_num_nodes);
154  active_nodes_.reserve(max_num_nodes);
155  }
156  const ArcIndex max_num_arcs = Graphs<Graph>::ArcReservation(*graph_);
157  if (max_num_arcs > 0) {
158  residual_arc_capacity_.Reserve(-max_num_arcs, max_num_arcs - 1);
159  residual_arc_capacity_.SetAll(0);
160  }
161 }
162 
163 template <typename Graph>
165  SCOPED_TIME_STAT(&stats_);
166  bool ok = true;
167  for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
168  if (residual_arc_capacity_[arc] < 0) {
169  ok = false;
170  }
171  }
172  return ok;
173 }
174 
175 template <typename Graph>
177  FlowQuantity new_capacity) {
178  SCOPED_TIME_STAT(&stats_);
179  DCHECK_LE(0, new_capacity);
180  DCHECK(IsArcDirect(arc));
181  const FlowQuantity free_capacity = residual_arc_capacity_[arc];
182  const FlowQuantity capacity_delta = new_capacity - Capacity(arc);
183  if (capacity_delta == 0) {
184  return; // Nothing to do.
185  }
186  status_ = NOT_SOLVED;
187  if (free_capacity + capacity_delta >= 0) {
188  // The above condition is true if one of the two conditions is true:
189  // 1/ (capacity_delta > 0), meaning we are increasing the capacity
190  // 2/ (capacity_delta < 0 && free_capacity + capacity_delta >= 0)
191  // meaning we are reducing the capacity, but that the capacity
192  // reduction is not larger than the free capacity.
193  DCHECK((capacity_delta > 0) ||
194  (capacity_delta < 0 && free_capacity + capacity_delta >= 0));
195  residual_arc_capacity_.Set(arc, free_capacity + capacity_delta);
196  DCHECK_LE(0, residual_arc_capacity_[arc]);
197  } else {
198  // Note that this breaks the preflow invariants but it is currently not an
199  // issue since we restart from scratch on each Solve() and we set the status
200  // to NOT_SOLVED.
201  //
202  // TODO(user): The easiest is probably to allow negative node excess in
203  // other places than the source, but the current implementation does not
204  // deal with this.
205  SetCapacityAndClearFlow(arc, new_capacity);
206  }
207 }
208 
209 template <typename Graph>
211  SCOPED_TIME_STAT(&stats_);
212  DCHECK(IsArcValid(arc));
213  DCHECK_GE(new_flow, 0);
214  const FlowQuantity capacity = Capacity(arc);
215  DCHECK_GE(capacity, new_flow);
216 
217  // Note that this breaks the preflow invariants but it is currently not an
218  // issue since we restart from scratch on each Solve() and we set the status
219  // to NOT_SOLVED.
220  residual_arc_capacity_.Set(Opposite(arc), -new_flow);
221  residual_arc_capacity_.Set(arc, capacity - new_flow);
222  status_ = NOT_SOLVED;
223 }
224 
225 template <typename Graph>
227  std::vector<NodeIndex>* result) {
228  ComputeReachableNodes<false>(source_, result);
229 }
230 
231 template <typename Graph>
232 void GenericMaxFlow<Graph>::GetSinkSideMinCut(std::vector<NodeIndex>* result) {
233  ComputeReachableNodes<true>(sink_, result);
234 }
235 
236 template <typename Graph>
238  SCOPED_TIME_STAT(&stats_);
239  bool ok = true;
240  if (node_excess_[source_] != -node_excess_[sink_]) {
241  LOG(DFATAL) << "-node_excess_[source_] = " << -node_excess_[source_]
242  << " != node_excess_[sink_] = " << node_excess_[sink_];
243  ok = false;
244  }
245  for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
246  if (node != source_ && node != sink_) {
247  if (node_excess_[node] != 0) {
248  LOG(DFATAL) << "node_excess_[" << node << "] = " << node_excess_[node]
249  << " != 0";
250  ok = false;
251  }
252  }
253  }
254  for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
255  const ArcIndex opposite = Opposite(arc);
256  const FlowQuantity direct_capacity = residual_arc_capacity_[arc];
257  const FlowQuantity opposite_capacity = residual_arc_capacity_[opposite];
258  if (direct_capacity < 0) {
259  LOG(DFATAL) << "residual_arc_capacity_[" << arc
260  << "] = " << direct_capacity << " < 0";
261  ok = false;
262  }
263  if (opposite_capacity < 0) {
264  LOG(DFATAL) << "residual_arc_capacity_[" << opposite
265  << "] = " << opposite_capacity << " < 0";
266  ok = false;
267  }
268  // The initial capacity of the direct arcs is non-negative.
269  if (direct_capacity + opposite_capacity < 0) {
270  LOG(DFATAL) << "initial capacity [" << arc
271  << "] = " << direct_capacity + opposite_capacity << " < 0";
272  ok = false;
273  }
274  }
275  return ok;
276 }
277 
278 template <typename Graph>
280  SCOPED_TIME_STAT(&stats_);
281 
282  // We simply compute the reachability from the source in the residual graph.
283  const NodeIndex num_nodes = graph_->num_nodes();
284  std::vector<bool> is_reached(num_nodes, false);
285  std::vector<NodeIndex> to_process;
286 
287  to_process.push_back(source_);
288  is_reached[source_] = true;
289  while (!to_process.empty()) {
290  const NodeIndex node = to_process.back();
291  to_process.pop_back();
292  for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
293  it.Next()) {
294  const ArcIndex arc = it.Index();
295  if (residual_arc_capacity_[arc] > 0) {
296  const NodeIndex head = graph_->Head(arc);
297  if (!is_reached[head]) {
298  is_reached[head] = true;
299  to_process.push_back(head);
300  }
301  }
302  }
303  }
304  return is_reached[sink_];
305 }
306 
307 template <typename Graph>
309  DCHECK(IsActive(node));
310  for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
311  it.Next()) {
312  const ArcIndex arc = it.Index();
313  DCHECK(!IsAdmissible(arc)) << DebugString("CheckRelabelPrecondition:", arc);
314  }
315  return true;
316 }
317 
318 template <typename Graph>
319 std::string GenericMaxFlow<Graph>::DebugString(const std::string& context,
320  ArcIndex arc) const {
321  const NodeIndex tail = Tail(arc);
322  const NodeIndex head = Head(arc);
323  return absl::StrFormat(
324  "%s Arc %d, from %d to %d, "
325  "Capacity = %d, Residual capacity = %d, "
326  "Flow = residual capacity for reverse arc = %d, "
327  "Height(tail) = %d, Height(head) = %d, "
328  "Excess(tail) = %d, Excess(head) = %d",
329  context, arc, tail, head, Capacity(arc), residual_arc_capacity_[arc],
330  Flow(arc), node_potential_[tail], node_potential_[head],
331  node_excess_[tail], node_excess_[head]);
332 }
333 
334 template <typename Graph>
336  status_ = NOT_SOLVED;
337  if (check_input_ && !CheckInputConsistency()) {
338  status_ = BAD_INPUT;
339  return false;
340  }
341  InitializePreflow();
342 
343  // Deal with the case when source_ or sink_ is not inside graph_.
344  // Since they are both specified independently of the graph, we do need to
345  // take care of this corner case.
346  const NodeIndex num_nodes = graph_->num_nodes();
347  if (sink_ >= num_nodes || source_ >= num_nodes) {
348  // Behave like a normal graph where source_ and sink_ are disconnected.
349  // Note that the arc flow is set to 0 by InitializePreflow().
350  status_ = OPTIMAL;
351  return true;
352  }
353  if (use_global_update_) {
354  RefineWithGlobalUpdate();
355  } else {
356  Refine();
357  }
358  if (check_result_) {
359  if (!CheckResult()) {
360  status_ = BAD_RESULT;
361  return false;
362  }
363  if (GetOptimalFlow() < kMaxFlowQuantity && AugmentingPathExists()) {
364  LOG(ERROR) << "The algorithm terminated, but the flow is not maximal!";
365  status_ = BAD_RESULT;
366  return false;
367  }
368  }
369  DCHECK_EQ(node_excess_[sink_], -node_excess_[source_]);
370  status_ = OPTIMAL;
371  if (GetOptimalFlow() == kMaxFlowQuantity && AugmentingPathExists()) {
372  // In this case, we are sure that the flow is > kMaxFlowQuantity.
373  status_ = INT_OVERFLOW;
374  }
375  IF_STATS_ENABLED(VLOG(1) << stats_.StatString());
376  return true;
377 }
378 
379 template <typename Graph>
381  SCOPED_TIME_STAT(&stats_);
382  // InitializePreflow() clears the whole flow that could have been computed
383  // by a previous Solve(). This is not optimal in terms of complexity.
384  // TODO(user): find a way to make the re-solving incremental (not an obvious
385  // task, and there has not been a lot of literature on the subject.)
386  node_excess_.SetAll(0);
387  const ArcIndex num_arcs = graph_->num_arcs();
388  for (ArcIndex arc = 0; arc < num_arcs; ++arc) {
389  SetCapacityAndClearFlow(arc, Capacity(arc));
390  }
391 
392  // All the initial heights are zero except for the source whose height is
393  // equal to the number of nodes and will never change during the algorithm.
394  node_potential_.SetAll(0);
395  node_potential_.Set(source_, graph_->num_nodes());
396 
397  // Initially no arcs are admissible except maybe the one leaving the source,
398  // but we treat the source in a special way, see
399  // SaturateOutgoingArcsFromSource().
400  const NodeIndex num_nodes = graph_->num_nodes();
401  for (NodeIndex node = 0; node < num_nodes; ++node) {
402  first_admissible_arc_[node] = Graph::kNilArc;
403  }
404 }
405 
406 // Note(user): Calling this function will break the property on the node
407 // potentials because of the way we cancel flow on cycle. However, we only call
408 // that at the end of the algorithm, or just before a GlobalUpdate() that will
409 // restore the precondition on the node potentials.
410 template <typename Graph>
412  SCOPED_TIME_STAT(&stats_);
413  const NodeIndex num_nodes = graph_->num_nodes();
414 
415  // We implement a variation of Tarjan's strongly connected component algorithm
416  // to detect cycles published in: Tarjan, R. E. (1972), "Depth-first search
417  // and linear graph algorithms", SIAM Journal on Computing. A description can
418  // also be found in wikipedia.
419 
420  // Stored nodes are settled nodes already stored in the
421  // reverse_topological_order (except the sink_ that we do not actually store).
422  std::vector<bool> stored(num_nodes, false);
423  stored[sink_] = true;
424 
425  // The visited nodes that are not yet stored are all the nodes from the
426  // source_ to the current node in the current dfs branch.
427  std::vector<bool> visited(num_nodes, false);
428  visited[sink_] = true;
429 
430  // Stack of arcs to explore in the dfs search.
431  // The current node is Head(arc_stack.back()).
432  std::vector<ArcIndex> arc_stack;
433 
434  // Increasing list of indices into the arc_stack that correspond to the list
435  // of arcs in the current dfs branch from the source_ to the current node.
436  std::vector<int> index_branch;
437 
438  // Node in reverse_topological_order in the final dfs tree.
439  std::vector<NodeIndex> reverse_topological_order;
440 
441  // We start by pushing all the outgoing arcs from the source on the stack to
442  // avoid special conditions in the code. As a result, source_ will not be
443  // stored in reverse_topological_order, and this is what we want.
444  for (OutgoingArcIterator it(*graph_, source_); it.Ok(); it.Next()) {
445  const ArcIndex arc = it.Index();
446  const FlowQuantity flow = Flow(arc);
447  if (flow > 0) {
448  arc_stack.push_back(arc);
449  }
450  }
451  visited[source_] = true;
452 
453  // Start the dfs on the subgraph formed by the direct arcs with positive flow.
454  while (!arc_stack.empty()) {
455  const NodeIndex node = Head(arc_stack.back());
456 
457  // If the node is visited, it means we have explored all its arcs and we
458  // have just backtracked in the dfs. Store it if it is not already stored
459  // and process the next arc on the stack.
460  if (visited[node]) {
461  if (!stored[node]) {
462  stored[node] = true;
463  reverse_topological_order.push_back(node);
464  DCHECK(!index_branch.empty());
465  index_branch.pop_back();
466  }
467  arc_stack.pop_back();
468  continue;
469  }
470 
471  // The node is a new unexplored node, add all its outgoing arcs with
472  // positive flow to the stack and go deeper in the dfs.
473  DCHECK(!stored[node]);
474  DCHECK(index_branch.empty() ||
475  (arc_stack.size() - 1 > index_branch.back()));
476  visited[node] = true;
477  index_branch.push_back(arc_stack.size() - 1);
478 
479  for (OutgoingArcIterator it(*graph_, node); it.Ok(); it.Next()) {
480  const ArcIndex arc = it.Index();
481  const FlowQuantity flow = Flow(arc);
482  const NodeIndex head = Head(arc);
483  if (flow > 0 && !stored[head]) {
484  if (!visited[head]) {
485  arc_stack.push_back(arc);
486  } else {
487  // There is a cycle.
488  // Find the first index to consider,
489  // arc_stack[index_branch[cycle_begin]] will be the first arc on the
490  // cycle.
491  int cycle_begin = index_branch.size();
492  while (cycle_begin > 0 &&
493  Head(arc_stack[index_branch[cycle_begin - 1]]) != head) {
494  --cycle_begin;
495  }
496 
497  // Compute the maximum flow that can be canceled on the cycle and the
498  // min index such that arc_stack[index_branch[i]] will be saturated.
499  FlowQuantity max_flow = flow;
500  int first_saturated_index = index_branch.size();
501  for (int i = index_branch.size() - 1; i >= cycle_begin; --i) {
502  const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
503  if (Flow(arc_on_cycle) <= max_flow) {
504  max_flow = Flow(arc_on_cycle);
505  first_saturated_index = i;
506  }
507  }
508 
509  // This is just here for a DCHECK() below.
510  const FlowQuantity excess = node_excess_[head];
511 
512  // Cancel the flow on the cycle, and set visited[node] = false for
513  // the node that will be backtracked over.
514  PushFlow(-max_flow, arc);
515  for (int i = index_branch.size() - 1; i >= cycle_begin; --i) {
516  const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
517  PushFlow(-max_flow, arc_on_cycle);
518  if (i >= first_saturated_index) {
519  DCHECK(visited[Head(arc_on_cycle)]);
520  visited[Head(arc_on_cycle)] = false;
521  } else {
522  DCHECK_GT(Flow(arc_on_cycle), 0);
523  }
524  }
525 
526  // This is a simple check that the flow was pushed properly.
527  DCHECK_EQ(excess, node_excess_[head]);
528 
529  // Backtrack the dfs just before index_branch[first_saturated_index].
530  // If the current node is still active, there is nothing to do.
531  if (first_saturated_index < index_branch.size()) {
532  arc_stack.resize(index_branch[first_saturated_index]);
533  index_branch.resize(first_saturated_index);
534 
535  // We backtracked over the current node, so there is no need to
536  // continue looping over its arcs.
537  break;
538  }
539  }
540  }
541  }
542  }
543  DCHECK(arc_stack.empty());
544  DCHECK(index_branch.empty());
545 
546  // Return the flow to the sink. Note that the sink_ and the source_ are not
547  // stored in reverse_topological_order.
548  for (int i = 0; i < reverse_topological_order.size(); i++) {
549  const NodeIndex node = reverse_topological_order[i];
550  if (node_excess_[node] == 0) continue;
551  for (IncomingArcIterator it(*graph_, node); it.Ok(); it.Next()) {
552  const ArcIndex opposite_arc = Opposite(it.Index());
553  if (residual_arc_capacity_[opposite_arc] > 0) {
554  const FlowQuantity flow =
555  std::min(node_excess_[node], residual_arc_capacity_[opposite_arc]);
556  PushFlow(flow, opposite_arc);
557  if (node_excess_[node] == 0) break;
558  }
559  }
560  DCHECK_EQ(0, node_excess_[node]);
561  }
562  DCHECK_EQ(-node_excess_[source_], node_excess_[sink_]);
563 }
564 
565 template <typename Graph>
567  SCOPED_TIME_STAT(&stats_);
568  bfs_queue_.clear();
569  int queue_index = 0;
570  const NodeIndex num_nodes = graph_->num_nodes();
571  node_in_bfs_queue_.assign(num_nodes, false);
572  node_in_bfs_queue_[sink_] = true;
573  node_in_bfs_queue_[source_] = true;
574 
575  // We do two BFS in the reverse residual graph, one from the sink and one from
576  // the source. Because all the arcs from the source are saturated (except in
577  // presence of integer overflow), the source cannot reach the sink in the
578  // residual graph. However, we still want to relabel all the nodes that cannot
579  // reach the sink but can reach the source (because if they have excess, we
580  // need to push it back to the source).
581  //
582  // Note that the second pass is not needed here if we use a two-pass algorithm
583  // to return the flow to the source after we found the min cut.
584  const int num_passes = use_two_phase_algorithm_ ? 1 : 2;
585  for (int pass = 0; pass < num_passes; ++pass) {
586  if (pass == 0) {
587  bfs_queue_.push_back(sink_);
588  } else {
589  bfs_queue_.push_back(source_);
590  }
591 
592  while (queue_index != bfs_queue_.size()) {
593  const NodeIndex node = bfs_queue_[queue_index];
594  ++queue_index;
595  const NodeIndex candidate_distance = node_potential_[node] + 1;
596  for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
597  it.Next()) {
598  const ArcIndex arc = it.Index();
599  const NodeIndex head = Head(arc);
600 
601  // Skip the arc if the height of head was already set to the correct
602  // value (Remember we are doing reverse BFS).
603  if (node_in_bfs_queue_[head]) continue;
604 
605  // TODO(user): By using more memory we can speed this up quite a bit by
606  // avoiding to take the opposite arc here, too options:
607  // - if (residual_arc_capacity_[arc] != arc_capacity_[arc])
608  // - if (opposite_arc_is_admissible_[arc]) // need updates.
609  // Experiment with the first option shows more than 10% gain on this
610  // function running time, which is the bottleneck on many instances.
611  const ArcIndex opposite_arc = Opposite(arc);
612  if (residual_arc_capacity_[opposite_arc] > 0) {
613  // Note(user): We used to have a DCHECK_GE(candidate_distance,
614  // node_potential_[head]); which is always true except in the case
615  // where we can push more than kMaxFlowQuantity out of the source. The
616  // problem comes from the fact that in this case, we call
617  // PushFlowExcessBackToSource() in the middle of the algorithm. The
618  // later call will break the properties of the node potential. Note
619  // however, that this function will recompute a good node potential
620  // for all the nodes and thus fix the issue.
621 
622  // If head is active, we can steal some or all of its excess.
623  // This brings a huge gain on some problems.
624  // Note(user): I haven't seen this anywhere in the literature.
625  // TODO(user): Investigate more and maybe write a publication :)
626  if (node_excess_[head] > 0) {
627  const FlowQuantity flow = std::min(
628  node_excess_[head], residual_arc_capacity_[opposite_arc]);
629  PushFlow(flow, opposite_arc);
630 
631  // If the arc became saturated, it is no longer in the residual
632  // graph, so we do not need to consider head at this time.
633  if (residual_arc_capacity_[opposite_arc] == 0) continue;
634  }
635 
636  // Note that there is no need to touch first_admissible_arc_[node]
637  // because of the relaxed Relabel() we use.
638  node_potential_[head] = candidate_distance;
639  node_in_bfs_queue_[head] = true;
640  bfs_queue_.push_back(head);
641  }
642  }
643  }
644  }
645 
646  // At the end of the search, some nodes may not be in the bfs_queue_. Such
647  // nodes cannot reach the sink_ or source_ in the residual graph, so there is
648  // no point trying to push flow toward them. We obtain this effect by setting
649  // their height to something unreachable.
650  //
651  // Note that this also prevents cycling due to our anti-overflow procedure.
652  // For instance, suppose there is an edge s -> n outgoing from the source. If
653  // node n has no other connection and some excess, we will push the flow back
654  // to the source, but if we don't update the height of n
655  // SaturateOutgoingArcsFromSource() will push the flow to n again.
656  // TODO(user): This is another argument for another anti-overflow algorithm.
657  for (NodeIndex node = 0; node < num_nodes; ++node) {
658  if (!node_in_bfs_queue_[node]) {
659  node_potential_[node] = 2 * num_nodes - 1;
660  }
661  }
662 
663  // Reset the active nodes. Doing it like this pushes the nodes in increasing
664  // order of height. Note that bfs_queue_[0] is the sink_ so we skip it.
665  DCHECK(IsEmptyActiveNodeContainer());
666  for (int i = 1; i < bfs_queue_.size(); ++i) {
667  const NodeIndex node = bfs_queue_[i];
668  if (node_excess_[node] > 0) {
669  DCHECK(IsActive(node));
670  PushActiveNode(node);
671  }
672  }
673 }
674 
675 template <typename Graph>
677  SCOPED_TIME_STAT(&stats_);
678  const NodeIndex num_nodes = graph_->num_nodes();
679 
680  // If sink_ or source_ already have kMaxFlowQuantity, then there is no
681  // point pushing more flow since it will cause an integer overflow.
682  if (node_excess_[sink_] == kMaxFlowQuantity) return false;
683  if (node_excess_[source_] == -kMaxFlowQuantity) return false;
684 
685  bool flow_pushed = false;
686  for (OutgoingArcIterator it(*graph_, source_); it.Ok(); it.Next()) {
687  const ArcIndex arc = it.Index();
688  const FlowQuantity flow = residual_arc_capacity_[arc];
689 
690  // This is a special IsAdmissible() condition for the source.
691  if (flow == 0 || node_potential_[Head(arc)] >= num_nodes) continue;
692 
693  // We are careful in case the sum of the flow out of the source is greater
694  // than kMaxFlowQuantity to avoid overflow.
695  const FlowQuantity current_flow_out_of_source = -node_excess_[source_];
696  DCHECK_GE(flow, 0) << flow;
697  DCHECK_GE(current_flow_out_of_source, 0) << current_flow_out_of_source;
698  const FlowQuantity capped_flow =
699  kMaxFlowQuantity - current_flow_out_of_source;
700  if (capped_flow < flow) {
701  // We push as much flow as we can so the current flow on the network will
702  // be kMaxFlowQuantity.
703 
704  // Since at the beginning of the function, current_flow_out_of_source
705  // was different from kMaxFlowQuantity, we are sure to have pushed some
706  // flow before if capped_flow is 0.
707  if (capped_flow == 0) return true;
708  PushFlow(capped_flow, arc);
709  return true;
710  }
711  PushFlow(flow, arc);
712  flow_pushed = true;
713  }
714  DCHECK_LE(node_excess_[source_], 0);
715  return flow_pushed;
716 }
717 
718 template <typename Graph>
720  SCOPED_TIME_STAT(&stats_);
721  // TODO(user): Do not allow a zero flow after fixing the UniformMaxFlow code.
722  DCHECK_GE(residual_arc_capacity_[Opposite(arc)] + flow, 0);
723  DCHECK_GE(residual_arc_capacity_[arc] - flow, 0);
724 
725  // node_excess_ should be always greater than or equal to 0 except for the
726  // source where it should always be smaller than or equal to 0. Note however
727  // that we cannot check this because when we cancel the flow on a cycle in
728  // PushFlowExcessBackToSource(), we may break this invariant during the
729  // operation even if it is still valid at the end.
730 
731  // Update the residual capacity of the arc and its opposite arc.
732  residual_arc_capacity_[arc] -= flow;
733  residual_arc_capacity_[Opposite(arc)] += flow;
734 
735  // Update the excesses at the tail and head of the arc.
736  node_excess_[Tail(arc)] -= flow;
737  node_excess_[Head(arc)] += flow;
738 }
739 
740 template <typename Graph>
742  SCOPED_TIME_STAT(&stats_);
743  DCHECK(IsEmptyActiveNodeContainer());
744  const NodeIndex num_nodes = graph_->num_nodes();
745  for (NodeIndex node = 0; node < num_nodes; ++node) {
746  if (IsActive(node)) {
747  if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes) {
748  continue;
749  }
750  PushActiveNode(node);
751  }
752  }
753 }
754 
755 template <typename Graph>
757  SCOPED_TIME_STAT(&stats_);
758  // Usually SaturateOutgoingArcsFromSource() will saturate all the arcs from
759  // the source in one go, and we will loop just once. But in case we can push
760  // more than kMaxFlowQuantity out of the source the loop is as follow:
761  // - Push up to kMaxFlowQuantity out of the source on the admissible outgoing
762  // arcs. Stop if no flow was pushed.
763  // - Compute the current max-flow. This will push some flow back to the
764  // source and render more outgoing arcs from the source not admissible.
765  //
766  // TODO(user): This may not be the most efficient algorithm if we need to loop
767  // many times. An alternative may be to handle the source like the other nodes
768  // in the algorithm, initially putting an excess of kMaxFlowQuantity on it,
769  // and making the source active like any other node with positive excess. To
770  // investigate.
771  //
772  // TODO(user): The code below is buggy when more than kMaxFlowQuantity can be
773  // pushed out of the source (i.e. when we loop more than once in the while()).
774  // This is not critical, since this code is not used in the default algorithm
775  // computation. The issue is twofold:
776  // - InitializeActiveNodeContainer() doesn't push the nodes in
777  // the correct order.
778  // - PushFlowExcessBackToSource() may break the node potential properties, and
779  // we will need a call to GlobalUpdate() to fix that.
780  while (SaturateOutgoingArcsFromSource()) {
781  DCHECK(IsEmptyActiveNodeContainer());
782  InitializeActiveNodeContainer();
783  while (!IsEmptyActiveNodeContainer()) {
784  const NodeIndex node = GetAndRemoveFirstActiveNode();
785  if (node == source_ || node == sink_) continue;
786  Discharge(node);
787  }
788  if (use_two_phase_algorithm_) {
789  PushFlowExcessBackToSource();
790  }
791  }
792 }
793 
794 template <typename Graph>
796  SCOPED_TIME_STAT(&stats_);
797 
798  // TODO(user): This should be graph_->num_nodes(), but ebert graph does not
799  // have a correct size if the highest index nodes have no arcs.
800  const NodeIndex num_nodes = Graphs<Graph>::NodeReservation(*graph_);
801  std::vector<int> skip_active_node;
802 
803  while (SaturateOutgoingArcsFromSource()) {
804  int num_skipped;
805  do {
806  num_skipped = 0;
807  skip_active_node.assign(num_nodes, 0);
808  skip_active_node[sink_] = 2;
809  skip_active_node[source_] = 2;
810  GlobalUpdate();
811  while (!IsEmptyActiveNodeContainer()) {
812  const NodeIndex node = GetAndRemoveFirstActiveNode();
813  if (skip_active_node[node] > 1) {
814  if (node != sink_ && node != source_) ++num_skipped;
815  continue;
816  }
817  const NodeIndex old_height = node_potential_[node];
818  Discharge(node);
819 
820  // The idea behind this is that if a node height augments by more than
821  // one, then it is likely to push flow back the way it came. This can
822  // lead to very costly loops. A bad case is: source -> n1 -> n2 and n2
823  // just recently isolated from the sink. Then n2 will push flow back to
824  // n1, and n1 to n2 and so on. The height of each node will increase by
825  // steps of two until the height of the source is reached, which can
826  // take a long time. If the chain is longer, the situation is even
827  // worse. The behavior of this heuristic is related to the Gap
828  // heuristic.
829  //
830  // Note that the global update will fix all such cases efficiently. So
831  // the idea is to discharge the active node as much as possible, and
832  // then do a global update.
833  //
834  // We skip a node when this condition was true 2 times to avoid doing a
835  // global update too frequently.
836  if (node_potential_[node] > old_height + 1) {
837  ++skip_active_node[node];
838  }
839  }
840  } while (num_skipped > 0);
841  if (use_two_phase_algorithm_) {
842  PushFlowExcessBackToSource();
843  }
844  }
845 }
846 
847 template <typename Graph>
849  SCOPED_TIME_STAT(&stats_);
850  const NodeIndex num_nodes = graph_->num_nodes();
851  while (true) {
852  DCHECK(IsActive(node));
853  for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node,
854  first_admissible_arc_[node]);
855  it.Ok(); it.Next()) {
856  const ArcIndex arc = it.Index();
857  if (IsAdmissible(arc)) {
858  DCHECK(IsActive(node));
859  const NodeIndex head = Head(arc);
860  if (node_excess_[head] == 0) {
861  // The push below will make the node active for sure. Note that we may
862  // push the sink_, but that is handled properly in Refine().
863  PushActiveNode(head);
864  }
865  const FlowQuantity delta =
866  std::min(node_excess_[node], residual_arc_capacity_[arc]);
867  PushFlow(delta, arc);
868  if (node_excess_[node] == 0) {
869  first_admissible_arc_[node] = arc; // arc may still be admissible.
870  return;
871  }
872  }
873  }
874  Relabel(node);
875  if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes) break;
876  }
877 }
878 
879 template <typename Graph>
881  SCOPED_TIME_STAT(&stats_);
882  // Because we use a relaxed version, this is no longer true if the
883  // first_admissible_arc_[node] was not actually the first arc!
884  // DCHECK(CheckRelabelPrecondition(node));
886  ArcIndex first_admissible_arc = Graph::kNilArc;
887  for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
888  it.Next()) {
889  const ArcIndex arc = it.Index();
890  if (residual_arc_capacity_[arc] > 0) {
891  // Update min_height only for arcs with available capacity.
892  NodeHeight head_height = node_potential_[Head(arc)];
893  if (head_height < min_height) {
894  min_height = head_height;
895  first_admissible_arc = arc;
896 
897  // We found an admissible arc at the current height, just stop there.
898  // This is the true first_admissible_arc_[node].
899  if (min_height + 1 == node_potential_[node]) break;
900  }
901  }
902  }
903  DCHECK_NE(first_admissible_arc, Graph::kNilArc);
904  node_potential_[node] = min_height + 1;
905 
906  // Note that after a Relabel(), the loop will continue in Discharge(), and
907  // we are sure that all the arcs before first_admissible_arc are not
908  // admissible since their height is > min_height.
909  first_admissible_arc_[node] = first_admissible_arc;
910 }
911 
912 template <typename Graph>
914  return Graphs<Graph>::OppositeArc(*graph_, arc);
915 }
916 
917 template <typename Graph>
919  return IsArcValid(arc) && arc >= 0;
920 }
921 
922 template <typename Graph>
924  return Graphs<Graph>::IsArcValid(*graph_, arc);
925 }
926 
927 template <typename Graph>
930 
931 template <typename Graph>
932 template <bool reverse>
934  NodeIndex start, std::vector<NodeIndex>* result) {
935  // If start is not a valid node index, it can reach only itself.
936  // Note(user): This is needed because source and sink are given independently
937  // of the graph and sometimes before it is even constructed.
938  const NodeIndex num_nodes = graph_->num_nodes();
939  if (start >= num_nodes) {
940  result->clear();
941  result->push_back(start);
942  return;
943  }
944  bfs_queue_.clear();
945  node_in_bfs_queue_.assign(num_nodes, false);
946 
947  int queue_index = 0;
948  bfs_queue_.push_back(start);
949  node_in_bfs_queue_[start] = true;
950  while (queue_index != bfs_queue_.size()) {
951  const NodeIndex node = bfs_queue_[queue_index];
952  ++queue_index;
953  for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
954  it.Next()) {
955  const ArcIndex arc = it.Index();
956  const NodeIndex head = Head(arc);
957  if (node_in_bfs_queue_[head]) continue;
958  if (residual_arc_capacity_[reverse ? Opposite(arc) : arc] == 0) continue;
959  node_in_bfs_queue_[head] = true;
960  bfs_queue_.push_back(head);
961  }
962  }
963  *result = bfs_queue_;
964 }
965 
966 template <typename Graph>
969  model.set_problem_type(FlowModel::MAX_FLOW);
970  for (int n = 0; n < graph_->num_nodes(); ++n) {
971  Node* node = model.add_node();
972  node->set_id(n);
973  if (n == source_) node->set_supply(1);
974  if (n == sink_) node->set_supply(-1);
975  }
976  for (int a = 0; a < graph_->num_arcs(); ++a) {
977  Arc* arc = model.add_arc();
978  arc->set_tail_node_id(graph_->Tail(a));
979  arc->set_head_node_id(graph_->Head(a));
980  arc->set_capacity(Capacity(a));
981  }
982  return model;
983 }
984 
985 // Explicit instantiations that can be used by a client.
986 //
987 // TODO(user): moves this code out of a .cc file and include it at the end of
988 // the header so it can work with any graph implementation ?
989 template <>
992 template <>
993 const FlowQuantity
996 template <>
997 const FlowQuantity
1000 template <>
1001 const FlowQuantity
1004 
1005 template class GenericMaxFlow<StarGraph>;
1009 
1010 } // namespace operations_research
int64_t head
int64_t min
Definition: alldiff_cst.cc:139
FlowQuantity OptimalFlow() const
Definition: max_flow.cc:106
#define VLOG(verboselevel)
Definition: base/logging.h:979
StarGraph ::IncomingArcIterator IncomingArcIterator
Definition: max_flow.h:322
const int ERROR
Definition: log_severity.h:32
#define LOG(severity)
Definition: base/logging.h:416
#define SCOPED_TIME_STAT(stats)
Definition: stats.h:438
GRBmodel * model
CpSolverResponse Solve(const CpModelProto &model_proto)
Solves the given CpModelProto and returns an instance of CpSolverResponse.
#define DCHECK_GT(val1, val2)
Definition: base/logging.h:891
int64_t tail
Status Solve(NodeIndex source, NodeIndex sink)
Definition: max_flow.cc:55
void set_tail_node_id(::PROTOBUF_NAMESPACE_ID::int64 value)
ArcIndex AddArcWithCapacity(NodeIndex tail, NodeIndex head, FlowQuantity capacity)
Definition: max_flow.cc:28
void set_id(::PROTOBUF_NAMESPACE_ID::int64 value)
int64_t max
Definition: alldiff_cst.cc:140
GenericMaxFlow(const Graph *graph, NodeIndex source, NodeIndex sink)
Definition: max_flow.cc:126
#define DCHECK_NE(val1, val2)
Definition: base/logging.h:887
void set_supply(::PROTOBUF_NAMESPACE_ID::int64 value)
NodeIndex Tail(ArcIndex arc) const
Definition: max_flow.cc:43
int64_t capacity
FlowQuantity Flow(ArcIndex arc) const
Definition: max_flow.cc:108
#define DCHECK_GE(val1, val2)
Definition: base/logging.h:890
void set_head_node_id(::PROTOBUF_NAMESPACE_ID::int64 value)
void SetArcCapacity(ArcIndex arc, FlowQuantity capacity)
Definition: max_flow.cc:51
int64_t delta
Definition: resource.cc:1692
ListGraph Graph
Definition: graph.h:2361
#define DCHECK(condition)
Definition: base/logging.h:885
void GetSinkSideMinCut(std::vector< NodeIndex > *result)
Definition: max_flow.cc:115
#define DCHECK_EQ(val1, val2)
Definition: base/logging.h:886
StarGraph ::OutgoingOrOppositeIncomingArcIterator OutgoingOrOppositeIncomingArcIterator
Definition: max_flow.h:321
#define DCHECK_LE(val1, val2)
Definition: base/logging.h:888
Collection of objects used to extend the Constraint Solver library.
NodeIndex Head(ArcIndex arc) const
Definition: max_flow.cc:45
void set_capacity(::PROTOBUF_NAMESPACE_ID::int64 value)
void GetSourceSideMinCut(std::vector< NodeIndex > *result)
Definition: max_flow.cc:110
GurobiMPCallbackContext * context
FlowQuantity Capacity(ArcIndex arc) const
Definition: max_flow.cc:47
StarGraph ::OutgoingArcIterator OutgoingArcIterator
Definition: max_flow.h:319
#define IF_STATS_ENABLED(instructions)
Definition: stats.h:437
int64_t a