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) {
139 template <
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),
157 DCHECK(graph->IsNodeValid(source));
158 DCHECK(graph->IsNodeValid(sink));
160 if (max_num_nodes > 0) {
161 node_excess_.Reserve(0, max_num_nodes - 1);
162 node_excess_.SetAll(0);
163 node_potential_.Reserve(0, max_num_nodes - 1);
164 node_potential_.SetAll(0);
165 first_admissible_arc_.Reserve(0, max_num_nodes - 1);
166 first_admissible_arc_.SetAll(Graph::kNilArc);
167 bfs_queue_.reserve(max_num_nodes);
168 active_nodes_.reserve(max_num_nodes);
171 if (max_num_arcs > 0) {
172 residual_arc_capacity_.Reserve(-max_num_arcs, max_num_arcs - 1);
173 residual_arc_capacity_.SetAll(0);
177 template <
typename Graph>
181 for (
ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
182 if (residual_arc_capacity_[arc] < 0) {
189 template <
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);
223 template <
typename Graph>
234 residual_arc_capacity_.Set(Opposite(arc), -new_flow);
235 residual_arc_capacity_.Set(arc,
capacity - new_flow);
236 status_ = NOT_SOLVED;
239 template <
typename Graph>
241 std::vector<NodeIndex>* result) {
242 ComputeReachableNodes<false>(source_, result);
245 template <
typename Graph>
247 ComputeReachableNodes<true>(sink_, result);
250 template <
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";
292 template <
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_];
321 template <
typename Graph>
327 DCHECK(!IsAdmissible(arc)) << DebugString(
"CheckRelabelPrecondition:", arc);
332 template <
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]);
348 template <
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;
393 template <
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;
424 template <
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;
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_]);
579 template <
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);
689 template <
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);
732 template <
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;
754 template <
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);
769 template <
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();
808 template <
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();
861 template <
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;
893 template <
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;
926 template <
typename Graph>
931 template <
typename Graph>
933 return IsArcValid(arc) && arc >= 0;
936 template <
typename Graph>
941 template <
typename Graph>
945 template <
typename Graph>
946 template <
bool reverse>
948 NodeIndex start, std::vector<NodeIndex>* result) {
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_;
980 template <
typename Graph>
983 model.set_problem_type(FlowModelProto::MAX_FLOW);
984 for (
int n = 0; n < graph_->num_nodes(); ++n) {
990 for (
int a = 0;
a < graph_->num_arcs(); ++
a) {
void set_tail(int64_t value)
FlowModelProto CreateFlowModelProto(NodeIndex source, NodeIndex sink) const
void set_capacity(int64_t value)
StarGraph ::ArcIndex ArcIndex
FlowQuantity OptimalFlow() const
void set_id(int64_t value)
#define VLOG(verboselevel)
StarGraph ::IncomingArcIterator IncomingArcIterator
#define SCOPED_TIME_STAT(stats)
CpSolverResponse Solve(const CpModelProto &model_proto)
Solves the given CpModelProto and returns an instance of CpSolverResponse.
void set_head(int64_t value)
#define DCHECK_GT(val1, val2)
Status Solve(NodeIndex source, NodeIndex sink)
static constexpr ProblemType MAX_FLOW
ArcIndex AddArcWithCapacity(NodeIndex tail, NodeIndex head, FlowQuantity capacity)
GenericMaxFlow(const Graph *graph, NodeIndex source, NodeIndex sink)
#define DCHECK_NE(val1, val2)
NodeIndex Tail(ArcIndex arc) const
FlowQuantity Flow(ArcIndex arc) const
#define DCHECK_GE(val1, val2)
void SetArcCapacity(ArcIndex arc, FlowQuantity capacity)
#define DCHECK(condition)
void GetSinkSideMinCut(std::vector< NodeIndex > *result)
#define DCHECK_EQ(val1, val2)
StarGraph ::OutgoingOrOppositeIncomingArcIterator OutgoingOrOppositeIncomingArcIterator
#define DCHECK_LE(val1, val2)
StarGraph ::NodeIndex NodeIndex
Collection of objects used to extend the Constraint Solver library.
NodeIndex Head(ArcIndex arc) const
void set_supply(int64_t value)
void GetSourceSideMinCut(std::vector< NodeIndex > *result)
GurobiMPCallbackContext * context
NodeIndex NumNodes() const
FlowQuantity Capacity(ArcIndex arc) const
StarGraph ::OutgoingArcIterator OutgoingArcIterator
#define IF_STATS_ENABLED(instructions)