22#include "absl/memory/memory.h"
23#include "absl/strings/str_format.h"
24#include "absl/strings/string_view.h"
34 const ArcIndex num_arcs = arc_tail_.size();
35 num_nodes_ = std::max(num_nodes_,
tail + 1);
36 num_nodes_ = std::max(num_nodes_,
head + 1);
37 arc_tail_.push_back(
tail);
38 arc_head_.push_back(
head);
39 arc_capacity_.push_back(capacity);
52 return arc_capacity_[
arc];
56 arc_capacity_[
arc] = capacity;
60 const ArcIndex num_arcs = arc_capacity_.size();
61 arc_flow_.assign(num_arcs, 0);
62 underlying_max_flow_.reset();
63 underlying_graph_.reset();
65 if (source == sink || source < 0 || sink < 0) {
68 if (source >= num_nodes_ || sink >= num_nodes_) {
71 underlying_graph_ = std::make_unique<Graph>(num_nodes_, num_arcs);
72 underlying_graph_->AddNode(source);
73 underlying_graph_->AddNode(sink);
74 for (
int arc = 0;
arc < num_arcs; ++
arc) {
75 underlying_graph_->AddArc(arc_tail_[
arc], arc_head_[
arc]);
77 underlying_graph_->Build(&arc_permutation_);
78 underlying_max_flow_ = std::make_unique<GenericMaxFlow<Graph>>(
79 underlying_graph_.get(), source, sink);
82 arc < arc_permutation_.size() ? arc_permutation_[
arc] :
arc;
83 underlying_max_flow_->SetArcCapacity(permuted_arc, arc_capacity_[
arc]);
85 if (underlying_max_flow_->Solve()) {
86 optimal_flow_ = underlying_max_flow_->GetOptimalFlow();
89 arc < arc_permutation_.size() ? arc_permutation_[
arc] :
arc;
90 arc_flow_[
arc] = underlying_max_flow_->Flow(permuted_arc);
95 switch (underlying_max_flow_->status()) {
115 if (underlying_max_flow_ ==
nullptr)
return;
116 underlying_max_flow_->GetSourceSideMinCut(result);
120 if (underlying_max_flow_ ==
nullptr)
return;
121 underlying_max_flow_->GetSinkSideMinCut(result);
126 FlowModelProto
model;
127 model.set_problem_type(FlowModelProto::MAX_FLOW);
128 for (
int n = 0; n < num_nodes_; ++n) {
129 FlowNodeProto* node =
model.add_nodes();
131 if (n == source) node->set_supply(1);
132 if (n == sink) node->set_supply(-1);
134 for (
int a = 0;
a < arc_tail_.size(); ++
a) {
135 FlowArcProto*
arc =
model.add_arcs();
143template <
typename Graph>
149 residual_arc_capacity_(),
150 first_admissible_arc_(),
154 use_global_update_(true),
155 use_two_phase_algorithm_(true),
156 process_node_by_height_(true),
164 if (max_num_nodes > 0) {
175 if (max_num_arcs > 0) {
181template <
typename Graph>
186 if (residual_arc_capacity_[
arc] < 0) {
193template <
typename Graph>
197 DCHECK_LE(0, new_capacity);
198 DCHECK(IsArcDirect(
arc));
201 if (capacity_delta == 0) {
205 if (free_capacity + capacity_delta >= 0) {
211 DCHECK((capacity_delta > 0) ||
212 (capacity_delta < 0 && free_capacity + capacity_delta >= 0));
213 residual_arc_capacity_.Set(
arc, free_capacity + capacity_delta);
214 DCHECK_LE(0, residual_arc_capacity_[
arc]);
223 SetCapacityAndClearFlow(
arc, new_capacity);
227template <
typename Graph>
230 DCHECK(IsArcValid(
arc));
231 DCHECK_GE(new_flow, 0);
233 DCHECK_GE(capacity, new_flow);
238 residual_arc_capacity_.Set(Opposite(
arc), -new_flow);
239 residual_arc_capacity_.Set(
arc, capacity - new_flow);
243template <
typename Graph>
245 std::vector<NodeIndex>* result) {
246 ComputeReachableNodes<false>(source_, result);
249template <
typename Graph>
251 ComputeReachableNodes<true>(sink_, result);
254template <
typename Graph>
258 if (node_excess_[source_] != -node_excess_[sink_]) {
259 LOG(DFATAL) <<
"-node_excess_[source_] = " << -node_excess_[source_]
260 <<
" != node_excess_[sink_] = " << node_excess_[sink_];
263 for (
NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
264 if (node != source_ && node != sink_) {
265 if (node_excess_[node] != 0) {
266 LOG(DFATAL) <<
"node_excess_[" << node <<
"] = " << node_excess_[node]
275 const FlowQuantity opposite_capacity = residual_arc_capacity_[opposite];
276 if (direct_capacity < 0) {
277 LOG(DFATAL) <<
"residual_arc_capacity_[" <<
arc
278 <<
"] = " << direct_capacity <<
" < 0";
281 if (opposite_capacity < 0) {
282 LOG(DFATAL) <<
"residual_arc_capacity_[" << opposite
283 <<
"] = " << opposite_capacity <<
" < 0";
287 if (direct_capacity + opposite_capacity < 0) {
288 LOG(DFATAL) <<
"initial capacity [" <<
arc
289 <<
"] = " << direct_capacity + opposite_capacity <<
" < 0";
296template <
typename Graph>
301 const NodeIndex num_nodes = graph_->num_nodes();
302 std::vector<bool> is_reached(num_nodes,
false);
303 std::vector<NodeIndex> to_process;
305 to_process.push_back(source_);
306 is_reached[source_] =
true;
307 while (!to_process.empty()) {
308 const NodeIndex node = to_process.back();
309 to_process.pop_back();
313 if (residual_arc_capacity_[
arc] > 0) {
315 if (!is_reached[
head]) {
316 is_reached[
head] =
true;
317 to_process.push_back(
head);
322 return is_reached[sink_];
325template <
typename Graph>
327 DCHECK(IsActive(node));
331 DCHECK(!IsAdmissible(
arc)) << DebugString(
"CheckRelabelPrecondition:",
arc);
336template <
typename Graph>
341 return absl::StrFormat(
342 "%s Arc %d, from %d to %d, "
343 "Capacity = %d, Residual capacity = %d, "
344 "Flow = residual capacity for reverse arc = %d, "
345 "Height(tail) = %d, Height(head) = %d, "
346 "Excess(tail) = %d, Excess(head) = %d",
348 Flow(
arc), node_potential_[
tail], node_potential_[
head],
349 node_excess_[
tail], node_excess_[
head]);
352template <
typename Graph>
355 if (check_input_ && !CheckInputConsistency()) {
364 const NodeIndex num_nodes = graph_->num_nodes();
365 if (sink_ >= num_nodes || source_ >= num_nodes) {
371 if (use_global_update_) {
372 RefineWithGlobalUpdate();
377 if (!CheckResult()) {
378 status_ = BAD_RESULT;
381 if (GetOptimalFlow() < kMaxFlowQuantity && AugmentingPathExists()) {
382 LOG(ERROR) <<
"The algorithm terminated, but the flow is not maximal!";
383 status_ = BAD_RESULT;
387 DCHECK_EQ(node_excess_[sink_], -node_excess_[source_]);
389 if (GetOptimalFlow() == kMaxFlowQuantity && AugmentingPathExists()) {
391 status_ = INT_OVERFLOW;
397template <
typename Graph>
404 node_excess_.SetAll(0);
405 const ArcIndex num_arcs = graph_->num_arcs();
407 SetCapacityAndClearFlow(
arc, Capacity(
arc));
412 node_potential_.SetAll(0);
413 node_potential_.Set(source_, graph_->num_nodes());
418 const NodeIndex num_nodes = graph_->num_nodes();
419 for (
NodeIndex node = 0; node < num_nodes; ++node) {
428template <
typename Graph>
431 const NodeIndex num_nodes = graph_->num_nodes();
440 std::vector<bool> stored(num_nodes,
false);
441 stored[sink_] =
true;
445 std::vector<bool> visited(num_nodes,
false);
446 visited[sink_] =
true;
450 std::vector<ArcIndex> arc_stack;
454 std::vector<int> index_branch;
457 std::vector<NodeIndex> reverse_topological_order;
469 visited[source_] =
true;
472 while (!arc_stack.empty()) {
481 reverse_topological_order.push_back(node);
482 DCHECK(!index_branch.empty());
483 index_branch.pop_back();
485 arc_stack.pop_back();
491 DCHECK(!stored[node]);
492 DCHECK(index_branch.empty() ||
493 (arc_stack.size() - 1 > index_branch.back()));
494 visited[node] =
true;
495 index_branch.push_back(arc_stack.size() - 1);
497 for (OutgoingArcIterator it(*graph_, node); it.Ok(); it.Next()) {
501 if (flow > 0 && !stored[
head]) {
509 int cycle_begin = index_branch.size();
510 while (cycle_begin > 0 &&
511 Head(arc_stack[index_branch[cycle_begin - 1]]) !=
head) {
518 int first_saturated_index = index_branch.size();
519 for (
int i = index_branch.size() - 1; i >= cycle_begin; --i) {
520 const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
521 if (Flow(arc_on_cycle) <= max_flow) {
522 max_flow = Flow(arc_on_cycle);
523 first_saturated_index = i;
532 PushFlow(-max_flow,
arc);
533 for (
int i = index_branch.size() - 1; i >= cycle_begin; --i) {
534 const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
535 PushFlow(-max_flow, arc_on_cycle);
536 if (i >= first_saturated_index) {
537 DCHECK(visited[Head(arc_on_cycle)]);
538 visited[Head(arc_on_cycle)] =
false;
540 DCHECK_GT(Flow(arc_on_cycle), 0);
545 DCHECK_EQ(excess, node_excess_[
head]);
549 if (first_saturated_index < index_branch.size()) {
550 arc_stack.resize(index_branch[first_saturated_index]);
551 index_branch.resize(first_saturated_index);
561 DCHECK(arc_stack.empty());
562 DCHECK(index_branch.empty());
566 for (
int i = 0;
i < reverse_topological_order.size();
i++) {
567 const NodeIndex node = reverse_topological_order[
i];
568 if (node_excess_[node] == 0)
continue;
569 for (IncomingArcIterator it(*graph_, node); it.Ok(); it.Next()) {
570 const ArcIndex opposite_arc = Opposite(it.Index());
571 if (residual_arc_capacity_[opposite_arc] > 0) {
573 std::min(node_excess_[node], residual_arc_capacity_[opposite_arc]);
574 PushFlow(flow, opposite_arc);
575 if (node_excess_[node] == 0)
break;
578 DCHECK_EQ(0, node_excess_[node]);
580 DCHECK_EQ(-node_excess_[source_], node_excess_[sink_]);
583template <
typename Graph>
588 const NodeIndex num_nodes = graph_->num_nodes();
589 node_in_bfs_queue_.assign(num_nodes,
false);
590 node_in_bfs_queue_[sink_] =
true;
591 node_in_bfs_queue_[source_] =
true;
602 const int num_passes = use_two_phase_algorithm_ ? 1 : 2;
603 for (
int pass = 0; pass < num_passes; ++pass) {
605 bfs_queue_.push_back(sink_);
607 bfs_queue_.push_back(source_);
610 while (queue_index != bfs_queue_.size()) {
611 const NodeIndex node = bfs_queue_[queue_index];
613 const NodeIndex candidate_distance = node_potential_[node] + 1;
621 if (node_in_bfs_queue_[
head])
continue;
630 if (residual_arc_capacity_[opposite_arc] > 0) {
644 if (node_excess_[
head] > 0) {
646 node_excess_[
head], residual_arc_capacity_[opposite_arc]);
647 PushFlow(flow, opposite_arc);
651 if (residual_arc_capacity_[opposite_arc] == 0)
continue;
656 node_potential_[
head] = candidate_distance;
657 node_in_bfs_queue_[
head] =
true;
658 bfs_queue_.push_back(
head);
675 for (
NodeIndex node = 0; node < num_nodes; ++node) {
676 if (!node_in_bfs_queue_[node]) {
677 node_potential_[node] = 2 * num_nodes - 1;
683 DCHECK(IsEmptyActiveNodeContainer());
684 for (
int i = 1; i < bfs_queue_.size(); ++i) {
686 if (node_excess_[node] > 0) {
687 DCHECK(IsActive(node));
688 PushActiveNode(node);
693template <
typename Graph>
696 const NodeIndex num_nodes = graph_->num_nodes();
700 if (node_excess_[sink_] == kMaxFlowQuantity)
return false;
701 if (node_excess_[source_] == -kMaxFlowQuantity)
return false;
703 bool flow_pushed =
false;
709 if (flow == 0 || node_potential_[Head(
arc)] >= num_nodes)
continue;
713 const FlowQuantity current_flow_out_of_source = -node_excess_[source_];
714 DCHECK_GE(flow, 0) << flow;
715 DCHECK_GE(current_flow_out_of_source, 0) << current_flow_out_of_source;
717 kMaxFlowQuantity - current_flow_out_of_source;
718 if (capped_flow < flow) {
725 if (capped_flow == 0)
return true;
726 PushFlow(capped_flow,
arc);
732 DCHECK_LE(node_excess_[source_], 0);
736template <
typename Graph>
740 DCHECK_GE(residual_arc_capacity_[Opposite(
arc)] + flow, 0);
741 DCHECK_GE(residual_arc_capacity_[
arc] - flow, 0);
750 residual_arc_capacity_[
arc] -= flow;
751 residual_arc_capacity_[Opposite(
arc)] += flow;
754 node_excess_[Tail(
arc)] -= flow;
755 node_excess_[Head(
arc)] += flow;
758template <
typename Graph>
761 DCHECK(IsEmptyActiveNodeContainer());
762 const NodeIndex num_nodes = graph_->num_nodes();
763 for (
NodeIndex node = 0; node < num_nodes; ++node) {
764 if (IsActive(node)) {
765 if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes) {
768 PushActiveNode(node);
773template <
typename Graph>
798 while (SaturateOutgoingArcsFromSource()) {
799 DCHECK(IsEmptyActiveNodeContainer());
800 InitializeActiveNodeContainer();
801 while (!IsEmptyActiveNodeContainer()) {
802 const NodeIndex node = GetAndRemoveFirstActiveNode();
803 if (node == source_ || node == sink_)
continue;
806 if (use_two_phase_algorithm_) {
807 PushFlowExcessBackToSource();
812template <
typename Graph>
819 std::vector<int> skip_active_node;
821 while (SaturateOutgoingArcsFromSource()) {
825 skip_active_node.assign(num_nodes, 0);
826 skip_active_node[sink_] = 2;
827 skip_active_node[source_] = 2;
829 while (!IsEmptyActiveNodeContainer()) {
830 const NodeIndex node = GetAndRemoveFirstActiveNode();
831 if (skip_active_node[node] > 1) {
832 if (node != sink_ && node != source_) ++num_skipped;
835 const NodeIndex old_height = node_potential_[node];
854 if (node_potential_[node] > old_height + 1) {
855 ++skip_active_node[node];
858 }
while (num_skipped > 0);
859 if (use_two_phase_algorithm_) {
860 PushFlowExcessBackToSource();
865template <
typename Graph>
868 const NodeIndex num_nodes = graph_->num_nodes();
870 DCHECK(IsActive(node));
872 first_admissible_arc_[node]);
873 it.
Ok(); it.Next()) {
875 if (IsAdmissible(
arc)) {
876 DCHECK(IsActive(node));
878 if (node_excess_[
head] == 0) {
881 PushActiveNode(
head);
884 std::min(node_excess_[node], residual_arc_capacity_[
arc]);
886 if (node_excess_[node] == 0) {
887 first_admissible_arc_[node] =
arc;
893 if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes)
break;
897template <
typename Graph>
903 NodeHeight min_height = std::numeric_limits<NodeHeight>::max();
908 if (residual_arc_capacity_[
arc] > 0) {
911 if (head_height < min_height) {
912 min_height = head_height;
913 first_admissible_arc =
arc;
917 if (min_height + 1 == node_potential_[node])
break;
922 node_potential_[node] = min_height + 1;
927 first_admissible_arc_[node] = first_admissible_arc;
930template <
typename Graph>
935template <
typename Graph>
937 return IsArcValid(
arc) &&
arc >= 0;
940template <
typename Graph>
945template <
typename Graph>
947 std::numeric_limits<FlowQuantity>::max();
949template <
typename Graph>
950template <
bool reverse>
956 const NodeIndex num_nodes = graph_->num_nodes();
957 if (
start >= num_nodes) {
959 result->push_back(
start);
963 node_in_bfs_queue_.assign(num_nodes,
false);
966 bfs_queue_.push_back(
start);
967 node_in_bfs_queue_[
start] =
true;
968 while (queue_index != bfs_queue_.size()) {
969 const NodeIndex node = bfs_queue_[queue_index];
975 if (node_in_bfs_queue_[
head])
continue;
976 if (residual_arc_capacity_[reverse ? Opposite(
arc) :
arc] == 0)
continue;
977 node_in_bfs_queue_[
head] =
true;
978 bfs_queue_.push_back(
head);
981 *result = bfs_queue_;
984template <
typename Graph>
986 FlowModelProto
model;
987 model.set_problem_type(FlowModelProto::MAX_FLOW);
988 for (
int n = 0; n < graph_->num_nodes(); ++n) {
989 FlowNodeProto* node =
model.add_nodes();
991 if (n == source_) node->set_supply(1);
992 if (n == sink_) node->set_supply(-1);
994 for (
int a = 0;
a < graph_->num_arcs(); ++
a) {
995 FlowArcProto*
arc =
model.add_arcs();
996 arc->set_tail(graph_->Tail(
a));
997 arc->set_head(graph_->Head(
a));
998 arc->set_capacity(Capacity(
a));
1009 std::numeric_limits<FlowQuantity>::max();
1013 std::numeric_limits<FlowQuantity>::max();
1017 std::numeric_limits<FlowQuantity>::max();
1021 std::numeric_limits<FlowQuantity>::max();
void GetSourceSideMinCut(std::vector< NodeIndex > *result)
void PushFlowExcessBackToSource()
void SetArcCapacity(ArcIndex arc, FlowQuantity new_capacity)
Sets the capacity for arc to new_capacity.
void Refine()
Performs optimization step.
void PushFlow(FlowQuantity flow, ArcIndex arc)
bool Solve()
Returns true if a maximum flow was solved.
StarGraph::OutgoingArcIterator OutgoingArcIterator
void InitializePreflow()
Initializes the preflow to a state that enables to run Refine.
const Graph * graph_
A pointer to the graph passed as argument.
bool SaturateOutgoingArcsFromSource()
StatsGroup stats_
Statistics about this class.
void InitializeActiveNodeContainer()
Initializes the container active_nodes_.
QuantityArray residual_arc_capacity_
ArcIndexArray first_admissible_arc_
An array representing the first admissible arc for each node in graph_.
void Discharge(NodeIndex node)
NodeHeightArray node_potential_
FlowModelProto CreateFlowModel()
Returns the protocol buffer representation of the current problem.
QuantityArray node_excess_
An array representing the excess for each node in graph_.
bool CheckInputConsistency() const
bool AugmentingPathExists() const
const Graph * graph() const
Returns the graph associated to the current object.
void RefineWithGlobalUpdate()
void SetArcFlow(ArcIndex arc, FlowQuantity new_flow)
Sets the flow for arc.
bool CheckRelabelPrecondition(NodeIndex node) const
Graph::NodeIndex NodeIndex
void Relabel(NodeIndex node)
bool IsArcDirect(ArcIndex arc) const
ArcIndex Opposite(ArcIndex arc) const
std::vector< NodeIndex > bfs_queue_
std::string DebugString(absl::string_view context, ArcIndex arc) const
bool IsArcValid(ArcIndex arc) const
std::vector< NodeIndex > active_nodes_
void GetSinkSideMinCut(std::vector< NodeIndex > *result)
void ComputeReachableNodes(NodeIndex start, std::vector< NodeIndex > *result)
GenericMaxFlow(const Graph *graph, NodeIndex source, NodeIndex sink)
ArcIndex NumArcs() const
Returns the current number of arcs in the graph.
NodeIndex NumNodes() const
FlowModelProto CreateFlowModelProto(NodeIndex source, NodeIndex sink) const
Creates the protocol buffer representation of the current problem.
FlowQuantity OptimalFlow() const
void SetArcCapacity(ArcIndex arc, FlowQuantity capacity)
ArcIndex AddArcWithCapacity(NodeIndex tail, NodeIndex head, FlowQuantity capacity)
void GetSinkSideMinCut(std::vector< NodeIndex > *result)
FlowQuantity Capacity(ArcIndex arc) const
@ BAD_RESULT
This should not happen. There was an error in our code (i.e. file a bug).
@ BAD_INPUT
The input is inconsistent (bad tail/head/capacity values).
Status Solve(NodeIndex source, NodeIndex sink)
NodeIndex Head(ArcIndex arc) const
void GetSourceSideMinCut(std::vector< NodeIndex > *result)
NodeIndex Tail(ArcIndex arc) const
FlowQuantity Flow(ArcIndex arc) const
bool Reserve(int64_t new_min_index, int64_t new_max_index)
void SetAll(T value)
Sets all the elements in the array to value.
bool IsNodeValid(NodeIndexType node) const
Returns true if the given node is a valid node of the graph.
static const int32_t kNilArc
GurobiMPCallbackContext * context
In SWIG mode, we don't want anything besides these top-level includes.
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
static ArcIndex ArcReservation(const Graph &graph)
static bool IsArcValid(const Graph &graph, ArcIndex arc)
static ArcIndex OppositeArc(const Graph &graph, ArcIndex arc)
static NodeIndex NodeReservation(const Graph &graph)