19#include "absl/memory/memory.h"
20#include "absl/strings/str_format.h"
30 const ArcIndex num_arcs = arc_tail_.size();
33 arc_tail_.push_back(
tail);
34 arc_head_.push_back(
head);
48 return arc_capacity_[arc];
56 const ArcIndex num_arcs = arc_capacity_.size();
57 arc_flow_.assign(num_arcs, 0);
58 underlying_max_flow_.reset();
59 underlying_graph_.reset();
61 if (source == sink || source < 0 || sink < 0) {
64 if (source >= num_nodes_ || sink >= num_nodes_) {
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]);
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) {
78 arc < arc_permutation_.size() ? arc_permutation_[arc] : arc;
79 underlying_max_flow_->SetArcCapacity(permuted_arc, arc_capacity_[arc]);
81 if (underlying_max_flow_->Solve()) {
82 optimal_flow_ = underlying_max_flow_->GetOptimalFlow();
83 for (
ArcIndex arc = 0; arc < num_arcs; ++arc) {
85 arc < arc_permutation_.size() ? arc_permutation_[arc] : arc;
86 arc_flow_[arc] = underlying_max_flow_->Flow(permuted_arc);
91 switch (underlying_max_flow_->status()) {
111 if (underlying_max_flow_ ==
nullptr)
return;
112 underlying_max_flow_->GetSourceSideMinCut(result);
116 if (underlying_max_flow_ ==
nullptr)
return;
117 underlying_max_flow_->GetSinkSideMinCut(result);
124 for (
int n = 0; n < num_nodes_; ++n) {
130 for (
int a = 0;
a < arc_tail_.size(); ++
a) {
139template <
typename Graph>
145 residual_arc_capacity_(),
146 first_admissible_arc_(),
150 use_global_update_(true),
151 use_two_phase_algorithm_(true),
152 process_node_by_height_(true),
160 if (max_num_nodes > 0) {
171 if (max_num_arcs > 0) {
177template <
typename Graph>
181 for (
ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
182 if (residual_arc_capacity_[arc] < 0) {
189template <
typename Graph>
195 const FlowQuantity free_capacity = residual_arc_capacity_[arc];
196 const FlowQuantity capacity_delta = new_capacity - Capacity(arc);
197 if (capacity_delta == 0) {
200 status_ = NOT_SOLVED;
201 if (free_capacity + capacity_delta >= 0) {
207 DCHECK((capacity_delta > 0) ||
208 (capacity_delta < 0 && free_capacity + capacity_delta >= 0));
209 residual_arc_capacity_.Set(arc, free_capacity + capacity_delta);
210 DCHECK_LE(0, residual_arc_capacity_[arc]);
219 SetCapacityAndClearFlow(arc, new_capacity);
223template <
typename Graph>
234 residual_arc_capacity_.Set(Opposite(arc), -new_flow);
235 residual_arc_capacity_.Set(arc,
capacity - new_flow);
236 status_ = NOT_SOLVED;
239template <
typename Graph>
241 std::vector<NodeIndex>* result) {
242 ComputeReachableNodes<false>(source_, result);
245template <
typename Graph>
247 ComputeReachableNodes<true>(sink_, result);
250template <
typename Graph>
254 if (node_excess_[source_] != -node_excess_[sink_]) {
255 LOG(DFATAL) <<
"-node_excess_[source_] = " << -node_excess_[source_]
256 <<
" != node_excess_[sink_] = " << node_excess_[sink_];
259 for (
NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
260 if (node != source_ && node != sink_) {
261 if (node_excess_[node] != 0) {
262 LOG(DFATAL) <<
"node_excess_[" << node <<
"] = " << node_excess_[node]
268 for (
ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
269 const ArcIndex opposite = Opposite(arc);
270 const FlowQuantity direct_capacity = residual_arc_capacity_[arc];
271 const FlowQuantity opposite_capacity = residual_arc_capacity_[opposite];
272 if (direct_capacity < 0) {
273 LOG(DFATAL) <<
"residual_arc_capacity_[" << arc
274 <<
"] = " << direct_capacity <<
" < 0";
277 if (opposite_capacity < 0) {
278 LOG(DFATAL) <<
"residual_arc_capacity_[" << opposite
279 <<
"] = " << opposite_capacity <<
" < 0";
283 if (direct_capacity + opposite_capacity < 0) {
284 LOG(DFATAL) <<
"initial capacity [" << arc
285 <<
"] = " << direct_capacity + opposite_capacity <<
" < 0";
292template <
typename Graph>
297 const NodeIndex num_nodes = graph_->num_nodes();
298 std::vector<bool> is_reached(num_nodes,
false);
299 std::vector<NodeIndex> to_process;
301 to_process.push_back(source_);
302 is_reached[source_] =
true;
303 while (!to_process.empty()) {
304 const NodeIndex node = to_process.back();
305 to_process.pop_back();
309 if (residual_arc_capacity_[arc] > 0) {
311 if (!is_reached[
head]) {
312 is_reached[
head] =
true;
313 to_process.push_back(
head);
318 return is_reached[sink_];
321template <
typename Graph>
327 DCHECK(!IsAdmissible(arc)) << DebugString(
"CheckRelabelPrecondition:", arc);
332template <
typename Graph>
337 return absl::StrFormat(
338 "%s Arc %d, from %d to %d, "
339 "Capacity = %d, Residual capacity = %d, "
340 "Flow = residual capacity for reverse arc = %d, "
341 "Height(tail) = %d, Height(head) = %d, "
342 "Excess(tail) = %d, Excess(head) = %d",
344 Flow(arc), node_potential_[
tail], node_potential_[
head],
345 node_excess_[
tail], node_excess_[
head]);
348template <
typename Graph>
350 status_ = NOT_SOLVED;
351 if (check_input_ && !CheckInputConsistency()) {
360 const NodeIndex num_nodes = graph_->num_nodes();
361 if (sink_ >= num_nodes || source_ >= num_nodes) {
367 if (use_global_update_) {
368 RefineWithGlobalUpdate();
373 if (!CheckResult()) {
374 status_ = BAD_RESULT;
377 if (GetOptimalFlow() < kMaxFlowQuantity && AugmentingPathExists()) {
378 LOG(ERROR) <<
"The algorithm terminated, but the flow is not maximal!";
379 status_ = BAD_RESULT;
383 DCHECK_EQ(node_excess_[sink_], -node_excess_[source_]);
385 if (GetOptimalFlow() == kMaxFlowQuantity && AugmentingPathExists()) {
387 status_ = INT_OVERFLOW;
393template <
typename Graph>
400 node_excess_.SetAll(0);
401 const ArcIndex num_arcs = graph_->num_arcs();
402 for (
ArcIndex arc = 0; arc < num_arcs; ++arc) {
403 SetCapacityAndClearFlow(arc, Capacity(arc));
408 node_potential_.SetAll(0);
409 node_potential_.Set(source_, graph_->num_nodes());
414 const NodeIndex num_nodes = graph_->num_nodes();
415 for (
NodeIndex node = 0; node < num_nodes; ++node) {
416 first_admissible_arc_[node] = Graph::kNilArc;
424template <
typename Graph>
427 const NodeIndex num_nodes = graph_->num_nodes();
436 std::vector<bool> stored(num_nodes,
false);
437 stored[sink_] =
true;
441 std::vector<bool> visited(num_nodes,
false);
442 visited[sink_] =
true;
446 std::vector<ArcIndex> arc_stack;
450 std::vector<int> index_branch;
453 std::vector<NodeIndex> reverse_topological_order;
462 arc_stack.push_back(arc);
465 visited[source_] =
true;
468 while (!arc_stack.empty()) {
469 const NodeIndex node = Head(arc_stack.back());
477 reverse_topological_order.push_back(node);
478 DCHECK(!index_branch.empty());
479 index_branch.pop_back();
481 arc_stack.pop_back();
488 DCHECK(index_branch.empty() ||
489 (arc_stack.size() - 1 > index_branch.back()));
490 visited[node] =
true;
491 index_branch.push_back(arc_stack.size() - 1);
497 if (flow > 0 && !stored[
head]) {
498 if (!visited[
head]) {
499 arc_stack.push_back(arc);
505 int cycle_begin = index_branch.size();
506 while (cycle_begin > 0 &&
507 Head(arc_stack[index_branch[cycle_begin - 1]]) !=
head) {
514 int first_saturated_index = index_branch.size();
515 for (
int i = index_branch.size() - 1; i >= cycle_begin; --i) {
516 const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
517 if (Flow(arc_on_cycle) <= max_flow) {
518 max_flow = Flow(arc_on_cycle);
519 first_saturated_index = i;
528 PushFlow(-max_flow, arc);
529 for (
int i = index_branch.size() - 1; i >= cycle_begin; --i) {
530 const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
531 PushFlow(-max_flow, arc_on_cycle);
532 if (i >= first_saturated_index) {
533 DCHECK(visited[Head(arc_on_cycle)]);
534 visited[Head(arc_on_cycle)] =
false;
545 if (first_saturated_index < index_branch.size()) {
546 arc_stack.resize(index_branch[first_saturated_index]);
547 index_branch.resize(first_saturated_index);
557 DCHECK(arc_stack.empty());
558 DCHECK(index_branch.empty());
562 for (
int i = 0; i < reverse_topological_order.size(); i++) {
563 const NodeIndex node = reverse_topological_order[i];
564 if (node_excess_[node] == 0)
continue;
565 for (IncomingArcIterator it(*graph_, node); it.Ok(); it.Next()) {
566 const ArcIndex opposite_arc = Opposite(it.Index());
567 if (residual_arc_capacity_[opposite_arc] > 0) {
569 std::min(node_excess_[node], residual_arc_capacity_[opposite_arc]);
570 PushFlow(flow, opposite_arc);
571 if (node_excess_[node] == 0)
break;
576 DCHECK_EQ(-node_excess_[source_], node_excess_[sink_]);
579template <
typename Graph>
584 const NodeIndex num_nodes = graph_->num_nodes();
585 node_in_bfs_queue_.assign(num_nodes,
false);
586 node_in_bfs_queue_[sink_] =
true;
587 node_in_bfs_queue_[source_] =
true;
598 const int num_passes = use_two_phase_algorithm_ ? 1 : 2;
599 for (
int pass = 0; pass < num_passes; ++pass) {
601 bfs_queue_.push_back(sink_);
603 bfs_queue_.push_back(source_);
606 while (queue_index != bfs_queue_.size()) {
607 const NodeIndex node = bfs_queue_[queue_index];
609 const NodeIndex candidate_distance = node_potential_[node] + 1;
617 if (node_in_bfs_queue_[
head])
continue;
625 const ArcIndex opposite_arc = Opposite(arc);
626 if (residual_arc_capacity_[opposite_arc] > 0) {
640 if (node_excess_[
head] > 0) {
642 node_excess_[
head], residual_arc_capacity_[opposite_arc]);
643 PushFlow(flow, opposite_arc);
647 if (residual_arc_capacity_[opposite_arc] == 0)
continue;
652 node_potential_[
head] = candidate_distance;
653 node_in_bfs_queue_[
head] =
true;
654 bfs_queue_.push_back(
head);
671 for (
NodeIndex node = 0; node < num_nodes; ++node) {
672 if (!node_in_bfs_queue_[node]) {
673 node_potential_[node] = 2 * num_nodes - 1;
679 DCHECK(IsEmptyActiveNodeContainer());
680 for (
int i = 1; i < bfs_queue_.size(); ++i) {
682 if (node_excess_[node] > 0) {
684 PushActiveNode(node);
689template <
typename Graph>
692 const NodeIndex num_nodes = graph_->num_nodes();
696 if (node_excess_[sink_] == kMaxFlowQuantity)
return false;
697 if (node_excess_[source_] == -kMaxFlowQuantity)
return false;
699 bool flow_pushed =
false;
705 if (flow == 0 || node_potential_[Head(arc)] >= num_nodes)
continue;
709 const FlowQuantity current_flow_out_of_source = -node_excess_[source_];
711 DCHECK_GE(current_flow_out_of_source, 0) << current_flow_out_of_source;
713 kMaxFlowQuantity - current_flow_out_of_source;
714 if (capped_flow < flow) {
721 if (capped_flow == 0)
return true;
722 PushFlow(capped_flow, arc);
732template <
typename Graph>
736 DCHECK_GE(residual_arc_capacity_[Opposite(arc)] + flow, 0);
737 DCHECK_GE(residual_arc_capacity_[arc] - flow, 0);
746 residual_arc_capacity_[arc] -= flow;
747 residual_arc_capacity_[Opposite(arc)] += flow;
750 node_excess_[Tail(arc)] -= flow;
751 node_excess_[Head(arc)] += flow;
754template <
typename Graph>
757 DCHECK(IsEmptyActiveNodeContainer());
758 const NodeIndex num_nodes = graph_->num_nodes();
759 for (
NodeIndex node = 0; node < num_nodes; ++node) {
760 if (IsActive(node)) {
761 if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes) {
764 PushActiveNode(node);
769template <
typename Graph>
794 while (SaturateOutgoingArcsFromSource()) {
795 DCHECK(IsEmptyActiveNodeContainer());
796 InitializeActiveNodeContainer();
797 while (!IsEmptyActiveNodeContainer()) {
798 const NodeIndex node = GetAndRemoveFirstActiveNode();
799 if (node == source_ || node == sink_)
continue;
802 if (use_two_phase_algorithm_) {
803 PushFlowExcessBackToSource();
808template <
typename Graph>
815 std::vector<int> skip_active_node;
817 while (SaturateOutgoingArcsFromSource()) {
821 skip_active_node.assign(num_nodes, 0);
822 skip_active_node[sink_] = 2;
823 skip_active_node[source_] = 2;
825 while (!IsEmptyActiveNodeContainer()) {
826 const NodeIndex node = GetAndRemoveFirstActiveNode();
827 if (skip_active_node[node] > 1) {
828 if (node != sink_ && node != source_) ++num_skipped;
831 const NodeIndex old_height = node_potential_[node];
850 if (node_potential_[node] > old_height + 1) {
851 ++skip_active_node[node];
854 }
while (num_skipped > 0);
855 if (use_two_phase_algorithm_) {
856 PushFlowExcessBackToSource();
861template <
typename Graph>
864 const NodeIndex num_nodes = graph_->num_nodes();
868 first_admissible_arc_[node]);
869 it.Ok(); it.Next()) {
871 if (IsAdmissible(arc)) {
874 if (node_excess_[
head] == 0) {
877 PushActiveNode(
head);
880 std::min(node_excess_[node], residual_arc_capacity_[arc]);
881 PushFlow(
delta, arc);
882 if (node_excess_[node] == 0) {
883 first_admissible_arc_[node] = arc;
889 if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes)
break;
893template <
typename Graph>
900 ArcIndex first_admissible_arc = Graph::kNilArc;
904 if (residual_arc_capacity_[arc] > 0) {
906 NodeHeight head_height = node_potential_[Head(arc)];
907 if (head_height < min_height) {
908 min_height = head_height;
909 first_admissible_arc = arc;
913 if (min_height + 1 == node_potential_[node])
break;
917 DCHECK_NE(first_admissible_arc, Graph::kNilArc);
918 node_potential_[node] = min_height + 1;
923 first_admissible_arc_[node] = first_admissible_arc;
926template <
typename Graph>
931template <
typename Graph>
933 return IsArcValid(arc) && arc >= 0;
936template <
typename Graph>
941template <
typename Graph>
945template <
typename Graph>
946template <
bool reverse>
952 const NodeIndex num_nodes = graph_->num_nodes();
953 if (
start >= num_nodes) {
955 result->push_back(
start);
959 node_in_bfs_queue_.assign(num_nodes,
false);
962 bfs_queue_.push_back(
start);
963 node_in_bfs_queue_[
start] =
true;
964 while (queue_index != bfs_queue_.size()) {
965 const NodeIndex node = bfs_queue_[queue_index];
971 if (node_in_bfs_queue_[
head])
continue;
972 if (residual_arc_capacity_[reverse ? Opposite(arc) : arc] == 0)
continue;
973 node_in_bfs_queue_[
head] =
true;
974 bfs_queue_.push_back(
head);
977 *result = bfs_queue_;
980template <
typename Graph>
984 for (
int n = 0; n < graph_->num_nodes(); ++n) {
990 for (
int a = 0;
a < graph_->num_arcs(); ++
a) {
#define DCHECK_LE(val1, val2)
#define DCHECK_NE(val1, val2)
#define DCHECK_GE(val1, val2)
#define DCHECK_GT(val1, val2)
#define DCHECK(condition)
#define DCHECK_EQ(val1, val2)
#define VLOG(verboselevel)
void set_head(int64_t value)
void set_capacity(int64_t value)
void set_tail(int64_t value)
static constexpr ProblemType MAX_FLOW
void set_supply(int64_t value)
void set_id(int64_t value)
Graph::OutgoingArcIterator OutgoingArcIterator
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()
const Graph * graph() const
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)