22 #include "absl/memory/memory.h"
23 #include "absl/strings/str_format.h"
33 const ArcIndex num_arcs = arc_tail_.size();
36 arc_tail_.push_back(
tail);
37 arc_head_.push_back(
head);
51 return arc_capacity_[
arc];
59 const ArcIndex num_arcs = arc_capacity_.size();
60 arc_flow_.assign(num_arcs, 0);
61 underlying_max_flow_.reset();
62 underlying_graph_.reset();
64 if (source == sink || source < 0 || sink < 0) {
67 if (source >= num_nodes_ || sink >= num_nodes_) {
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]);
76 underlying_graph_->Build(&arc_permutation_);
77 underlying_max_flow_ = std::make_unique<GenericMaxFlow<Graph>>(
78 underlying_graph_.get(), source, sink);
81 arc < arc_permutation_.size() ? arc_permutation_[
arc] :
arc;
82 underlying_max_flow_->SetArcCapacity(permuted_arc, arc_capacity_[
arc]);
84 if (underlying_max_flow_->Solve()) {
85 optimal_flow_ = underlying_max_flow_->GetOptimalFlow();
88 arc < arc_permutation_.size() ? arc_permutation_[
arc] :
arc;
89 arc_flow_[
arc] = underlying_max_flow_->Flow(permuted_arc);
94 switch (underlying_max_flow_->status()) {
114 if (underlying_max_flow_ ==
nullptr)
return;
115 underlying_max_flow_->GetSourceSideMinCut(result);
119 if (underlying_max_flow_ ==
nullptr)
return;
120 underlying_max_flow_->GetSinkSideMinCut(result);
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();
130 if (n == source) node->set_supply(1);
131 if (n == sink) node->set_supply(-1);
133 for (
int a = 0;
a < arc_tail_.size(); ++
a) {
134 FlowArcProto*
arc =
model.add_arcs();
142 template <
typename Graph>
148 residual_arc_capacity_(),
149 first_admissible_arc_(),
153 use_global_update_(true),
154 use_two_phase_algorithm_(true),
155 process_node_by_height_(true),
160 DCHECK(
graph->IsNodeValid(source));
161 DCHECK(
graph->IsNodeValid(sink));
163 if (max_num_nodes > 0) {
174 if (max_num_arcs > 0) {
180 template <
typename Graph>
185 if (residual_arc_capacity_[
arc] < 0) {
192 template <
typename Graph>
196 DCHECK_LE(0, new_capacity);
197 DCHECK(IsArcDirect(
arc));
200 if (capacity_delta == 0) {
204 if (free_capacity + capacity_delta >= 0) {
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]);
222 SetCapacityAndClearFlow(
arc, new_capacity);
226 template <
typename Graph>
229 DCHECK(IsArcValid(
arc));
230 DCHECK_GE(new_flow, 0);
237 residual_arc_capacity_.Set(Opposite(
arc), -new_flow);
238 residual_arc_capacity_.Set(
arc,
capacity - new_flow);
242 template <
typename Graph>
244 std::vector<NodeIndex>* result) {
245 ComputeReachableNodes<false>(source_, result);
248 template <
typename Graph>
250 ComputeReachableNodes<true>(sink_, result);
253 template <
typename Graph>
257 if (node_excess_[source_] != -node_excess_[sink_]) {
258 LOG(DFATAL) <<
"-node_excess_[source_] = " << -node_excess_[source_]
259 <<
" != node_excess_[sink_] = " << node_excess_[sink_];
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]
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";
280 if (opposite_capacity < 0) {
281 LOG(DFATAL) <<
"residual_arc_capacity_[" << opposite
282 <<
"] = " << opposite_capacity <<
" < 0";
286 if (direct_capacity + opposite_capacity < 0) {
287 LOG(DFATAL) <<
"initial capacity [" <<
arc
288 <<
"] = " << direct_capacity + opposite_capacity <<
" < 0";
295 template <
typename Graph>
300 const NodeIndex num_nodes = graph_->num_nodes();
301 std::vector<bool> is_reached(num_nodes,
false);
302 std::vector<NodeIndex> to_process;
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();
312 if (residual_arc_capacity_[
arc] > 0) {
314 if (!is_reached[
head]) {
315 is_reached[
head] =
true;
316 to_process.push_back(
head);
321 return is_reached[sink_];
324 template <
typename Graph>
326 DCHECK(IsActive(node));
330 DCHECK(!IsAdmissible(
arc)) << DebugString(
"CheckRelabelPrecondition:",
arc);
335 template <
typename Graph>
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",
347 Flow(
arc), node_potential_[
tail], node_potential_[
head],
348 node_excess_[
tail], node_excess_[
head]);
351 template <
typename Graph>
354 if (check_input_ && !CheckInputConsistency()) {
363 const NodeIndex num_nodes = graph_->num_nodes();
364 if (sink_ >= num_nodes || source_ >= num_nodes) {
370 if (use_global_update_) {
371 RefineWithGlobalUpdate();
376 if (!CheckResult()) {
377 status_ = BAD_RESULT;
380 if (GetOptimalFlow() < kMaxFlowQuantity && AugmentingPathExists()) {
381 LOG(ERROR) <<
"The algorithm terminated, but the flow is not maximal!";
382 status_ = BAD_RESULT;
386 DCHECK_EQ(node_excess_[sink_], -node_excess_[source_]);
388 if (GetOptimalFlow() == kMaxFlowQuantity && AugmentingPathExists()) {
390 status_ = INT_OVERFLOW;
396 template <
typename Graph>
403 node_excess_.SetAll(0);
406 SetCapacityAndClearFlow(
arc, Capacity(
arc));
411 node_potential_.SetAll(0);
412 node_potential_.Set(source_, graph_->num_nodes());
417 const NodeIndex num_nodes = graph_->num_nodes();
418 for (
NodeIndex node = 0; node < num_nodes; ++node) {
419 first_admissible_arc_[node] = Graph::kNilArc;
427 template <
typename Graph>
430 const NodeIndex num_nodes = graph_->num_nodes();
439 std::vector<bool> stored(num_nodes,
false);
440 stored[sink_] =
true;
444 std::vector<bool> visited(num_nodes,
false);
445 visited[sink_] =
true;
449 std::vector<ArcIndex> arc_stack;
453 std::vector<int> index_branch;
456 std::vector<NodeIndex> reverse_topological_order;
465 arc_stack.push_back(
arc);
468 visited[source_] =
true;
471 while (!arc_stack.empty()) {
472 const NodeIndex node = Head(arc_stack.back());
480 reverse_topological_order.push_back(node);
481 DCHECK(!index_branch.empty());
482 index_branch.pop_back();
484 arc_stack.pop_back();
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);
500 if (flow > 0 && !stored[
head]) {
501 if (!visited[
head]) {
508 int cycle_begin = index_branch.size();
509 while (cycle_begin > 0 &&
510 Head(arc_stack[index_branch[cycle_begin - 1]]) !=
head) {
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;
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;
539 DCHECK_GT(Flow(arc_on_cycle), 0);
544 DCHECK_EQ(excess, node_excess_[
head]);
548 if (first_saturated_index < index_branch.size()) {
549 arc_stack.resize(index_branch[first_saturated_index]);
550 index_branch.resize(first_saturated_index);
560 DCHECK(arc_stack.empty());
561 DCHECK(index_branch.empty());
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) {
572 std::min(node_excess_[node], residual_arc_capacity_[opposite_arc]);
573 PushFlow(flow, opposite_arc);
574 if (node_excess_[node] == 0)
break;
577 DCHECK_EQ(0, node_excess_[node]);
579 DCHECK_EQ(-node_excess_[source_], node_excess_[sink_]);
582 template <
typename Graph>
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;
601 const int num_passes = use_two_phase_algorithm_ ? 1 : 2;
602 for (
int pass = 0; pass < num_passes; ++pass) {
604 bfs_queue_.push_back(sink_);
606 bfs_queue_.push_back(source_);
609 while (queue_index != bfs_queue_.size()) {
610 const NodeIndex node = bfs_queue_[queue_index];
612 const NodeIndex candidate_distance = node_potential_[node] + 1;
620 if (node_in_bfs_queue_[
head])
continue;
629 if (residual_arc_capacity_[opposite_arc] > 0) {
643 if (node_excess_[
head] > 0) {
645 node_excess_[
head], residual_arc_capacity_[opposite_arc]);
646 PushFlow(flow, opposite_arc);
650 if (residual_arc_capacity_[opposite_arc] == 0)
continue;
655 node_potential_[
head] = candidate_distance;
656 node_in_bfs_queue_[
head] =
true;
657 bfs_queue_.push_back(
head);
674 for (
NodeIndex node = 0; node < num_nodes; ++node) {
675 if (!node_in_bfs_queue_[node]) {
676 node_potential_[node] = 2 * num_nodes - 1;
682 DCHECK(IsEmptyActiveNodeContainer());
683 for (
int i = 1; i < bfs_queue_.size(); ++i) {
685 if (node_excess_[node] > 0) {
686 DCHECK(IsActive(node));
687 PushActiveNode(node);
692 template <
typename Graph>
695 const NodeIndex num_nodes = graph_->num_nodes();
699 if (node_excess_[sink_] == kMaxFlowQuantity)
return false;
700 if (node_excess_[source_] == -kMaxFlowQuantity)
return false;
702 bool flow_pushed =
false;
708 if (flow == 0 || node_potential_[Head(
arc)] >= num_nodes)
continue;
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;
716 kMaxFlowQuantity - current_flow_out_of_source;
717 if (capped_flow < flow) {
724 if (capped_flow == 0)
return true;
725 PushFlow(capped_flow,
arc);
731 DCHECK_LE(node_excess_[source_], 0);
735 template <
typename Graph>
739 DCHECK_GE(residual_arc_capacity_[Opposite(
arc)] + flow, 0);
740 DCHECK_GE(residual_arc_capacity_[
arc] - flow, 0);
749 residual_arc_capacity_[
arc] -= flow;
750 residual_arc_capacity_[Opposite(
arc)] += flow;
753 node_excess_[Tail(
arc)] -= flow;
754 node_excess_[Head(
arc)] += flow;
757 template <
typename Graph>
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) {
767 PushActiveNode(node);
772 template <
typename Graph>
797 while (SaturateOutgoingArcsFromSource()) {
798 DCHECK(IsEmptyActiveNodeContainer());
799 InitializeActiveNodeContainer();
800 while (!IsEmptyActiveNodeContainer()) {
801 const NodeIndex node = GetAndRemoveFirstActiveNode();
802 if (node == source_ || node == sink_)
continue;
805 if (use_two_phase_algorithm_) {
806 PushFlowExcessBackToSource();
811 template <
typename Graph>
818 std::vector<int> skip_active_node;
820 while (SaturateOutgoingArcsFromSource()) {
824 skip_active_node.assign(num_nodes, 0);
825 skip_active_node[sink_] = 2;
826 skip_active_node[source_] = 2;
828 while (!IsEmptyActiveNodeContainer()) {
829 const NodeIndex node = GetAndRemoveFirstActiveNode();
830 if (skip_active_node[node] > 1) {
831 if (node != sink_ && node != source_) ++num_skipped;
834 const NodeIndex old_height = node_potential_[node];
853 if (node_potential_[node] > old_height + 1) {
854 ++skip_active_node[node];
857 }
while (num_skipped > 0);
858 if (use_two_phase_algorithm_) {
859 PushFlowExcessBackToSource();
864 template <
typename Graph>
867 const NodeIndex num_nodes = graph_->num_nodes();
869 DCHECK(IsActive(node));
871 first_admissible_arc_[node]);
872 it.Ok(); it.Next()) {
874 if (IsAdmissible(
arc)) {
875 DCHECK(IsActive(node));
877 if (node_excess_[
head] == 0) {
880 PushActiveNode(
head);
883 std::min(node_excess_[node], residual_arc_capacity_[
arc]);
885 if (node_excess_[node] == 0) {
886 first_admissible_arc_[node] =
arc;
892 if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes)
break;
896 template <
typename Graph>
903 ArcIndex first_admissible_arc = Graph::kNilArc;
907 if (residual_arc_capacity_[
arc] > 0) {
910 if (head_height < min_height) {
911 min_height = head_height;
912 first_admissible_arc =
arc;
916 if (min_height + 1 == node_potential_[node])
break;
920 DCHECK_NE(first_admissible_arc, Graph::kNilArc);
921 node_potential_[node] = min_height + 1;
926 first_admissible_arc_[node] = first_admissible_arc;
929 template <
typename Graph>
934 template <
typename Graph>
936 return IsArcValid(
arc) &&
arc >= 0;
939 template <
typename Graph>
944 template <
typename Graph>
948 template <
typename Graph>
949 template <
bool reverse>
955 const NodeIndex num_nodes = graph_->num_nodes();
956 if (
start >= num_nodes) {
958 result->push_back(
start);
962 node_in_bfs_queue_.assign(num_nodes,
false);
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];
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);
980 *result = bfs_queue_;
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();
990 if (n == source_) node->set_supply(1);
991 if (n == sink_) node->set_supply(-1);
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));
Graph::OutgoingArcIterator OutgoingArcIterator
const Graph * graph() const
bool CheckInputConsistency() const
void Relabel(NodeIndex node)
std::vector< NodeIndex > active_nodes_
void SetArcCapacity(ArcIndex arc, FlowQuantity new_capacity)
std::string DebugString(const std::string &context, ArcIndex arc) const
bool SaturateOutgoingArcsFromSource()
Graph::OutgoingOrOppositeIncomingArcIterator OutgoingOrOppositeIncomingArcIterator
bool CheckRelabelPrecondition(NodeIndex node) const
std::vector< NodeIndex > bfs_queue_
FlowModelProto CreateFlowModel()
ArcIndexArray first_admissible_arc_
void SetArcFlow(ArcIndex arc, FlowQuantity new_flow)
void PushFlowExcessBackToSource()
Graph::NodeIndex NodeIndex
void GetSourceSideMinCut(std::vector< NodeIndex > *result)
NodeHeightArray node_potential_
void InitializeActiveNodeContainer()
QuantityArray residual_arc_capacity_
void PushFlow(FlowQuantity flow, ArcIndex arc)
void ComputeReachableNodes(NodeIndex start, std::vector< NodeIndex > *result)
bool IsArcValid(ArcIndex arc) const
GenericMaxFlow(const Graph *graph, NodeIndex source, NodeIndex sink)
void RefineWithGlobalUpdate()
bool AugmentingPathExists() const
void GetSinkSideMinCut(std::vector< NodeIndex > *result)
ArcIndex Opposite(ArcIndex arc) const
bool IsArcDirect(ArcIndex arc) const
void Discharge(NodeIndex node)
QuantityArray node_excess_
FlowModelProto CreateFlowModelProto(NodeIndex source, NodeIndex sink) const
FlowQuantity Flow(ArcIndex arc) const
NodeIndex NumNodes() const
void GetSourceSideMinCut(std::vector< NodeIndex > *result)
Status Solve(NodeIndex source, NodeIndex sink)
FlowQuantity OptimalFlow() const
ArcIndex AddArcWithCapacity(NodeIndex tail, NodeIndex head, FlowQuantity capacity)
FlowQuantity Capacity(ArcIndex arc) const
NodeIndex Head(ArcIndex arc) const
NodeIndex Tail(ArcIndex arc) const
void SetArcCapacity(ArcIndex arc, FlowQuantity capacity)
void GetSinkSideMinCut(std::vector< NodeIndex > *result)
bool Reserve(int64_t new_min_index, int64_t new_max_index)
GurobiMPCallbackContext * context
Collection of objects used to extend the Constraint Solver library.
#define IF_STATS_ENABLED(instructions)
#define SCOPED_TIME_STAT(stats)
static ArcIndex ArcReservation(const Graph &graph)
static NodeIndex NodeReservation(const Graph &graph)
static bool IsArcValid(const Graph &graph, ArcIndex arc)
static ArcIndex OppositeArc(const Graph &graph, ArcIndex arc)
#define VLOG(verboselevel)