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