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);
121 if (underlying_max_flow_ ==
nullptr)
return FlowModel();
122 return underlying_max_flow_->CreateFlowModel();
125 template <
typename Graph>
131 residual_arc_capacity_(),
132 first_admissible_arc_(),
136 use_global_update_(true),
137 use_two_phase_algorithm_(true),
138 process_node_by_height_(true),
143 DCHECK(graph->IsNodeValid(source));
144 DCHECK(graph->IsNodeValid(sink));
146 if (max_num_nodes > 0) {
147 node_excess_.Reserve(0, max_num_nodes - 1);
148 node_excess_.SetAll(0);
149 node_potential_.Reserve(0, max_num_nodes - 1);
150 node_potential_.SetAll(0);
151 first_admissible_arc_.Reserve(0, max_num_nodes - 1);
152 first_admissible_arc_.SetAll(Graph::kNilArc);
153 bfs_queue_.reserve(max_num_nodes);
154 active_nodes_.reserve(max_num_nodes);
157 if (max_num_arcs > 0) {
158 residual_arc_capacity_.Reserve(-max_num_arcs, max_num_arcs - 1);
159 residual_arc_capacity_.SetAll(0);
163 template <
typename Graph>
167 for (
ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
168 if (residual_arc_capacity_[arc] < 0) {
175 template <
typename Graph>
181 const FlowQuantity free_capacity = residual_arc_capacity_[arc];
182 const FlowQuantity capacity_delta = new_capacity - Capacity(arc);
183 if (capacity_delta == 0) {
186 status_ = NOT_SOLVED;
187 if (free_capacity + capacity_delta >= 0) {
193 DCHECK((capacity_delta > 0) ||
194 (capacity_delta < 0 && free_capacity + capacity_delta >= 0));
195 residual_arc_capacity_.Set(arc, free_capacity + capacity_delta);
196 DCHECK_LE(0, residual_arc_capacity_[arc]);
205 SetCapacityAndClearFlow(arc, new_capacity);
209 template <
typename Graph>
220 residual_arc_capacity_.Set(Opposite(arc), -new_flow);
221 residual_arc_capacity_.Set(arc,
capacity - new_flow);
222 status_ = NOT_SOLVED;
225 template <
typename Graph>
227 std::vector<NodeIndex>* result) {
228 ComputeReachableNodes<false>(source_, result);
231 template <
typename Graph>
233 ComputeReachableNodes<true>(sink_, result);
236 template <
typename Graph>
240 if (node_excess_[source_] != -node_excess_[sink_]) {
241 LOG(DFATAL) <<
"-node_excess_[source_] = " << -node_excess_[source_]
242 <<
" != node_excess_[sink_] = " << node_excess_[sink_];
245 for (
NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
246 if (node != source_ && node != sink_) {
247 if (node_excess_[node] != 0) {
248 LOG(DFATAL) <<
"node_excess_[" << node <<
"] = " << node_excess_[node]
254 for (
ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
255 const ArcIndex opposite = Opposite(arc);
256 const FlowQuantity direct_capacity = residual_arc_capacity_[arc];
257 const FlowQuantity opposite_capacity = residual_arc_capacity_[opposite];
258 if (direct_capacity < 0) {
259 LOG(DFATAL) <<
"residual_arc_capacity_[" << arc
260 <<
"] = " << direct_capacity <<
" < 0";
263 if (opposite_capacity < 0) {
264 LOG(DFATAL) <<
"residual_arc_capacity_[" << opposite
265 <<
"] = " << opposite_capacity <<
" < 0";
269 if (direct_capacity + opposite_capacity < 0) {
270 LOG(DFATAL) <<
"initial capacity [" << arc
271 <<
"] = " << direct_capacity + opposite_capacity <<
" < 0";
278 template <
typename Graph>
283 const NodeIndex num_nodes = graph_->num_nodes();
284 std::vector<bool> is_reached(num_nodes,
false);
285 std::vector<NodeIndex> to_process;
287 to_process.push_back(source_);
288 is_reached[source_] =
true;
289 while (!to_process.empty()) {
290 const NodeIndex node = to_process.back();
291 to_process.pop_back();
295 if (residual_arc_capacity_[arc] > 0) {
297 if (!is_reached[
head]) {
298 is_reached[
head] =
true;
299 to_process.push_back(
head);
304 return is_reached[sink_];
307 template <
typename Graph>
313 DCHECK(!IsAdmissible(arc)) << DebugString(
"CheckRelabelPrecondition:", arc);
318 template <
typename Graph>
323 return absl::StrFormat(
324 "%s Arc %d, from %d to %d, " 325 "Capacity = %d, Residual capacity = %d, " 326 "Flow = residual capacity for reverse arc = %d, " 327 "Height(tail) = %d, Height(head) = %d, " 328 "Excess(tail) = %d, Excess(head) = %d",
330 Flow(arc), node_potential_[
tail], node_potential_[
head],
331 node_excess_[
tail], node_excess_[
head]);
334 template <
typename Graph>
336 status_ = NOT_SOLVED;
337 if (check_input_ && !CheckInputConsistency()) {
346 const NodeIndex num_nodes = graph_->num_nodes();
347 if (sink_ >= num_nodes || source_ >= num_nodes) {
353 if (use_global_update_) {
354 RefineWithGlobalUpdate();
359 if (!CheckResult()) {
360 status_ = BAD_RESULT;
363 if (GetOptimalFlow() < kMaxFlowQuantity && AugmentingPathExists()) {
364 LOG(
ERROR) <<
"The algorithm terminated, but the flow is not maximal!";
365 status_ = BAD_RESULT;
369 DCHECK_EQ(node_excess_[sink_], -node_excess_[source_]);
371 if (GetOptimalFlow() == kMaxFlowQuantity && AugmentingPathExists()) {
373 status_ = INT_OVERFLOW;
379 template <
typename Graph>
386 node_excess_.SetAll(0);
387 const ArcIndex num_arcs = graph_->num_arcs();
388 for (
ArcIndex arc = 0; arc < num_arcs; ++arc) {
389 SetCapacityAndClearFlow(arc, Capacity(arc));
394 node_potential_.SetAll(0);
395 node_potential_.Set(source_, graph_->num_nodes());
400 const NodeIndex num_nodes = graph_->num_nodes();
401 for (
NodeIndex node = 0; node < num_nodes; ++node) {
402 first_admissible_arc_[node] = Graph::kNilArc;
410 template <
typename Graph>
413 const NodeIndex num_nodes = graph_->num_nodes();
422 std::vector<bool> stored(num_nodes,
false);
423 stored[sink_] =
true;
427 std::vector<bool> visited(num_nodes,
false);
428 visited[sink_] =
true;
432 std::vector<ArcIndex> arc_stack;
436 std::vector<int> index_branch;
439 std::vector<NodeIndex> reverse_topological_order;
448 arc_stack.push_back(arc);
451 visited[source_] =
true;
454 while (!arc_stack.empty()) {
455 const NodeIndex node = Head(arc_stack.back());
463 reverse_topological_order.push_back(node);
464 DCHECK(!index_branch.empty());
465 index_branch.pop_back();
467 arc_stack.pop_back();
474 DCHECK(index_branch.empty() ||
475 (arc_stack.size() - 1 > index_branch.back()));
476 visited[node] =
true;
477 index_branch.push_back(arc_stack.size() - 1);
483 if (flow > 0 && !stored[
head]) {
484 if (!visited[
head]) {
485 arc_stack.push_back(arc);
491 int cycle_begin = index_branch.size();
492 while (cycle_begin > 0 &&
493 Head(arc_stack[index_branch[cycle_begin - 1]]) !=
head) {
500 int first_saturated_index = index_branch.size();
501 for (
int i = index_branch.size() - 1; i >= cycle_begin; --i) {
502 const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
503 if (Flow(arc_on_cycle) <= max_flow) {
504 max_flow = Flow(arc_on_cycle);
505 first_saturated_index = i;
514 PushFlow(-max_flow, arc);
515 for (
int i = index_branch.size() - 1; i >= cycle_begin; --i) {
516 const ArcIndex arc_on_cycle = arc_stack[index_branch[i]];
517 PushFlow(-max_flow, arc_on_cycle);
518 if (i >= first_saturated_index) {
519 DCHECK(visited[Head(arc_on_cycle)]);
520 visited[Head(arc_on_cycle)] =
false;
531 if (first_saturated_index < index_branch.size()) {
532 arc_stack.resize(index_branch[first_saturated_index]);
533 index_branch.resize(first_saturated_index);
543 DCHECK(arc_stack.empty());
544 DCHECK(index_branch.empty());
548 for (
int i = 0; i < reverse_topological_order.size(); i++) {
549 const NodeIndex node = reverse_topological_order[i];
550 if (node_excess_[node] == 0)
continue;
552 const ArcIndex opposite_arc = Opposite(it.Index());
553 if (residual_arc_capacity_[opposite_arc] > 0) {
555 std::min(node_excess_[node], residual_arc_capacity_[opposite_arc]);
556 PushFlow(flow, opposite_arc);
557 if (node_excess_[node] == 0)
break;
562 DCHECK_EQ(-node_excess_[source_], node_excess_[sink_]);
565 template <
typename Graph>
570 const NodeIndex num_nodes = graph_->num_nodes();
571 node_in_bfs_queue_.assign(num_nodes,
false);
572 node_in_bfs_queue_[sink_] =
true;
573 node_in_bfs_queue_[source_] =
true;
584 const int num_passes = use_two_phase_algorithm_ ? 1 : 2;
585 for (
int pass = 0; pass < num_passes; ++pass) {
587 bfs_queue_.push_back(sink_);
589 bfs_queue_.push_back(source_);
592 while (queue_index != bfs_queue_.size()) {
593 const NodeIndex node = bfs_queue_[queue_index];
595 const NodeIndex candidate_distance = node_potential_[node] + 1;
603 if (node_in_bfs_queue_[
head])
continue;
611 const ArcIndex opposite_arc = Opposite(arc);
612 if (residual_arc_capacity_[opposite_arc] > 0) {
626 if (node_excess_[
head] > 0) {
628 node_excess_[
head], residual_arc_capacity_[opposite_arc]);
629 PushFlow(flow, opposite_arc);
633 if (residual_arc_capacity_[opposite_arc] == 0)
continue;
638 node_potential_[
head] = candidate_distance;
639 node_in_bfs_queue_[
head] =
true;
640 bfs_queue_.push_back(
head);
657 for (
NodeIndex node = 0; node < num_nodes; ++node) {
658 if (!node_in_bfs_queue_[node]) {
659 node_potential_[node] = 2 * num_nodes - 1;
665 DCHECK(IsEmptyActiveNodeContainer());
666 for (
int i = 1; i < bfs_queue_.size(); ++i) {
668 if (node_excess_[node] > 0) {
670 PushActiveNode(node);
675 template <
typename Graph>
678 const NodeIndex num_nodes = graph_->num_nodes();
682 if (node_excess_[sink_] == kMaxFlowQuantity)
return false;
683 if (node_excess_[source_] == -kMaxFlowQuantity)
return false;
685 bool flow_pushed =
false;
691 if (flow == 0 || node_potential_[Head(arc)] >= num_nodes)
continue;
695 const FlowQuantity current_flow_out_of_source = -node_excess_[source_];
697 DCHECK_GE(current_flow_out_of_source, 0) << current_flow_out_of_source;
699 kMaxFlowQuantity - current_flow_out_of_source;
700 if (capped_flow < flow) {
707 if (capped_flow == 0)
return true;
708 PushFlow(capped_flow, arc);
718 template <
typename Graph>
722 DCHECK_GE(residual_arc_capacity_[Opposite(arc)] + flow, 0);
723 DCHECK_GE(residual_arc_capacity_[arc] - flow, 0);
732 residual_arc_capacity_[arc] -= flow;
733 residual_arc_capacity_[Opposite(arc)] += flow;
736 node_excess_[Tail(arc)] -= flow;
737 node_excess_[Head(arc)] += flow;
740 template <
typename Graph>
743 DCHECK(IsEmptyActiveNodeContainer());
744 const NodeIndex num_nodes = graph_->num_nodes();
745 for (
NodeIndex node = 0; node < num_nodes; ++node) {
746 if (IsActive(node)) {
747 if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes) {
750 PushActiveNode(node);
755 template <
typename Graph>
780 while (SaturateOutgoingArcsFromSource()) {
781 DCHECK(IsEmptyActiveNodeContainer());
782 InitializeActiveNodeContainer();
783 while (!IsEmptyActiveNodeContainer()) {
784 const NodeIndex node = GetAndRemoveFirstActiveNode();
785 if (node == source_ || node == sink_)
continue;
788 if (use_two_phase_algorithm_) {
789 PushFlowExcessBackToSource();
794 template <
typename Graph>
801 std::vector<int> skip_active_node;
803 while (SaturateOutgoingArcsFromSource()) {
807 skip_active_node.assign(num_nodes, 0);
808 skip_active_node[sink_] = 2;
809 skip_active_node[source_] = 2;
811 while (!IsEmptyActiveNodeContainer()) {
812 const NodeIndex node = GetAndRemoveFirstActiveNode();
813 if (skip_active_node[node] > 1) {
814 if (node != sink_ && node != source_) ++num_skipped;
817 const NodeIndex old_height = node_potential_[node];
836 if (node_potential_[node] > old_height + 1) {
837 ++skip_active_node[node];
840 }
while (num_skipped > 0);
841 if (use_two_phase_algorithm_) {
842 PushFlowExcessBackToSource();
847 template <
typename Graph>
850 const NodeIndex num_nodes = graph_->num_nodes();
854 first_admissible_arc_[node]);
855 it.Ok(); it.Next()) {
857 if (IsAdmissible(arc)) {
860 if (node_excess_[
head] == 0) {
863 PushActiveNode(
head);
866 std::min(node_excess_[node], residual_arc_capacity_[arc]);
867 PushFlow(
delta, arc);
868 if (node_excess_[node] == 0) {
869 first_admissible_arc_[node] = arc;
875 if (use_two_phase_algorithm_ && node_potential_[node] >= num_nodes)
break;
879 template <
typename Graph>
886 ArcIndex first_admissible_arc = Graph::kNilArc;
890 if (residual_arc_capacity_[arc] > 0) {
892 NodeHeight head_height = node_potential_[Head(arc)];
893 if (head_height < min_height) {
894 min_height = head_height;
895 first_admissible_arc = arc;
899 if (min_height + 1 == node_potential_[node])
break;
903 DCHECK_NE(first_admissible_arc, Graph::kNilArc);
904 node_potential_[node] = min_height + 1;
909 first_admissible_arc_[node] = first_admissible_arc;
912 template <
typename Graph>
917 template <
typename Graph>
919 return IsArcValid(arc) && arc >= 0;
922 template <
typename Graph>
927 template <
typename Graph>
931 template <
typename Graph>
932 template <
bool reverse>
934 NodeIndex start, std::vector<NodeIndex>* result) {
938 const NodeIndex num_nodes = graph_->num_nodes();
939 if (start >= num_nodes) {
941 result->push_back(start);
945 node_in_bfs_queue_.assign(num_nodes,
false);
948 bfs_queue_.push_back(start);
949 node_in_bfs_queue_[start] =
true;
950 while (queue_index != bfs_queue_.size()) {
951 const NodeIndex node = bfs_queue_[queue_index];
957 if (node_in_bfs_queue_[
head])
continue;
958 if (residual_arc_capacity_[reverse ? Opposite(arc) : arc] == 0)
continue;
959 node_in_bfs_queue_[
head] =
true;
960 bfs_queue_.push_back(
head);
963 *result = bfs_queue_;
966 template <
typename Graph>
969 model.set_problem_type(FlowModel::MAX_FLOW);
970 for (
int n = 0; n < graph_->num_nodes(); ++n) {
976 for (
int a = 0;
a < graph_->num_arcs(); ++
a) {
StarGraph ::ArcIndex ArcIndex
FlowQuantity OptimalFlow() const
#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.
FlowModel CreateFlowModelOfLastSolve()
#define DCHECK_GT(val1, val2)
Status Solve(NodeIndex source, NodeIndex sink)
void set_tail_node_id(::PROTOBUF_NAMESPACE_ID::int64 value)
ArcIndex AddArcWithCapacity(NodeIndex tail, NodeIndex head, FlowQuantity capacity)
void set_id(::PROTOBUF_NAMESPACE_ID::int64 value)
GenericMaxFlow(const Graph *graph, NodeIndex source, NodeIndex sink)
#define DCHECK_NE(val1, val2)
void set_supply(::PROTOBUF_NAMESPACE_ID::int64 value)
NodeIndex Tail(ArcIndex arc) const
FlowQuantity Flow(ArcIndex arc) const
#define DCHECK_GE(val1, val2)
void set_head_node_id(::PROTOBUF_NAMESPACE_ID::int64 value)
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_capacity(::PROTOBUF_NAMESPACE_ID::int64 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)