Google OR-Tools v9.12
a fast and portable software suite for combinatorial optimization
Loading...
Searching...
No Matches
min_cost_flow.cc
Go to the documentation of this file.
1// Copyright 2010-2025 Google LLC
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
15
16#include <algorithm>
17#include <cmath>
18#include <cstdint>
19#include <cstdlib>
20#include <limits>
21#include <string>
22#include <vector>
23
24#include "absl/base/attributes.h"
25#include "absl/flags/flag.h"
26#include "absl/log/check.h"
27#include "absl/strings/str_format.h"
28#include "absl/strings/string_view.h"
32#include "ortools/graph/graph.h"
34#include "ortools/util/stats.h"
35
36// TODO(user): Remove these flags and expose the parameters in the API.
37// New clients, please do not use these flags!
38ABSL_FLAG(int64_t, min_cost_flow_alpha, 5,
39 "Divide factor for epsilon at each refine step.");
40ABSL_FLAG(bool, min_cost_flow_check_feasibility, true,
41 "Check that the graph has enough capacity to send all supplies "
42 "and serve all demands. Also check that the sum of supplies "
43 "is equal to the sum of demands.");
44ABSL_FLAG(bool, min_cost_flow_check_result, true,
45 "Check that the result is valid.");
46
47namespace operations_research {
48
49template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
51 const Graph* graph)
52 : graph_(graph),
53 alpha_(absl::GetFlag(FLAGS_min_cost_flow_alpha)),
54 stats_("MinCostFlow"),
55 check_feasibility_(absl::GetFlag(FLAGS_min_cost_flow_check_feasibility)) {
56 // This class assumes we have negative reverse arcs.
57 static_assert(Graph::kHasNegativeReverseArcs);
58
59 const NodeIndex max_num_nodes = graph_->node_capacity();
60 if (max_num_nodes > 0) {
61 first_admissible_arc_.assign(max_num_nodes, Graph::kNilArc);
62 node_potential_.assign(max_num_nodes, 0);
63 node_excess_.assign(max_num_nodes, 0);
64 initial_node_excess_.assign(max_num_nodes, 0);
65 }
66 const ArcIndex max_num_arcs = graph_->arc_capacity();
67 if (max_num_arcs > 0) {
68 residual_arc_capacity_.Reserve(-max_num_arcs, max_num_arcs - 1);
69 residual_arc_capacity_.SetAll(0);
70 scaled_arc_unit_cost_.Reserve(-max_num_arcs, max_num_arcs - 1);
71 scaled_arc_unit_cost_.SetAll(0);
72 }
73}
74
75template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
77 NodeIndex node, FlowQuantity supply) {
78 DCHECK(graph_->IsNodeValid(node));
79 node_excess_[node] = supply;
80 initial_node_excess_[node] = supply;
81 status_ = NOT_SOLVED;
82 feasibility_checked_ = false;
83}
84
85template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
87 ArcIndex arc, ArcScaledCostType unit_cost) {
88 DCHECK(IsArcDirect(arc));
89 scaled_arc_unit_cost_.Set(arc, unit_cost);
90 scaled_arc_unit_cost_.Set(Opposite(arc), -scaled_arc_unit_cost_[arc]);
91 status_ = NOT_SOLVED;
92 feasibility_checked_ = false;
93}
94
95template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
97 ArcIndex arc, ArcFlowType new_capacity) {
98 DCHECK_LE(0, new_capacity);
99 DCHECK(IsArcDirect(arc));
100 const FlowQuantity free_capacity = residual_arc_capacity_[arc];
101 const FlowQuantity capacity_delta = new_capacity - Capacity(arc);
102 if (capacity_delta == 0) {
103 return; // Nothing to do.
104 }
105 status_ = NOT_SOLVED;
106 feasibility_checked_ = false;
107 const FlowQuantity new_availability = free_capacity + capacity_delta;
108 if (new_availability >= 0) {
109 // The above condition is true when one of two following holds:
110 // 1/ (capacity_delta > 0), meaning we are increasing the capacity
111 // 2/ (capacity_delta < 0 && free_capacity + capacity_delta >= 0)
112 // meaning we are reducing the capacity, but that the capacity
113 // reduction is not larger than the free capacity.
114 DCHECK((capacity_delta > 0) ||
115 (capacity_delta < 0 && new_availability >= 0));
116 residual_arc_capacity_.Set(arc, new_availability);
117 DCHECK_LE(0, residual_arc_capacity_[arc]);
118 } else {
119 // We have to reduce the flow on the arc, and update the excesses
120 // accordingly.
121 const FlowQuantity flow = residual_arc_capacity_[Opposite(arc)];
122 const FlowQuantity flow_excess = flow - new_capacity;
123 residual_arc_capacity_.Set(arc, 0);
124 residual_arc_capacity_.Set(Opposite(arc), new_capacity);
125 node_excess_[Tail(arc)] += flow_excess;
126 node_excess_[Head(arc)] -= flow_excess;
127 DCHECK_LE(0, residual_arc_capacity_[arc]);
128 DCHECK_LE(0, residual_arc_capacity_[Opposite(arc)]);
129 }
130}
131
132template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
133bool GenericMinCostFlow<Graph, ArcFlowType,
134 ArcScaledCostType>::CheckInputConsistency() {
135 const FlowQuantity kMaxFlow = std::numeric_limits<FlowQuantity>::max();
136
137 // First lets make sure supply == demand and the total supply/demand do not
138 // overflow.
139 FlowQuantity sum_of_supplies = 0;
140 FlowQuantity sum_of_demands = 0;
141 for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
142 const FlowQuantity excess = node_excess_[node];
143 if (excess > 0) {
144 sum_of_supplies = CapAdd(sum_of_supplies, excess);
145 if (sum_of_supplies >= kMaxFlow) {
146 status_ = BAD_CAPACITY_RANGE;
147 LOG(ERROR) << "Input consistency error: sum of supplies overflow";
148 return false;
149 }
150 } else if (excess < 0) {
151 sum_of_demands = CapAdd(sum_of_demands, -excess);
152 if (sum_of_demands >= kMaxFlow) {
153 status_ = BAD_CAPACITY_RANGE;
154 LOG(ERROR) << "Input consistency error: sum of demands overflow";
155 return false;
156 }
157 }
158 }
159 if (sum_of_supplies != sum_of_demands) {
160 status_ = UNBALANCED;
161 LOG(ERROR) << "Input consistency error: unbalanced problem";
162 return false;
163 }
164
165 std::vector<FlowQuantity> max_node_excess = node_excess_;
166 std::vector<FlowQuantity> min_node_excess = node_excess_;
167 for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
168 const FlowQuantity capacity = residual_arc_capacity_[arc];
169 CHECK_GE(capacity, 0);
170 if (capacity == 0) continue;
171 const int tail = graph_->Tail(arc);
172 const int head = graph_->Head(arc);
173 min_node_excess[tail] = CapSub(min_node_excess[tail], capacity);
174 max_node_excess[head] = CapAdd(max_node_excess[head], capacity);
175 }
176
177 const int num_nodes = graph_->num_nodes();
178 for (NodeIndex node = 0; node < num_nodes; ++node) {
179 if (max_node_excess[node] >= kMaxFlow ||
180 min_node_excess[node] <= -kMaxFlow) {
181 // Try to fix it.
182 // Some user just use arc with infinite capacity out of the source/sink.
183 // This is why we use CappedCapacity() for a name.
184 if (max_node_excess[node] < std::numeric_limits<ArcFlowType>::max()) {
185 // There is no point having an outgoing arc with more than this.
186 const ArcFlowType upper_bound =
187 std::max<ArcFlowType>(0, max_node_excess[node]);
188
189 // Adjust and recompute min_node_excess[node].
190 min_node_excess[node] = node_excess_[node];
191 for (OutgoingArcIterator it(*graph_, node); it.Ok(); it.Next()) {
192 const int arc = it.Index();
193 residual_arc_capacity_[arc] =
194 std::min(residual_arc_capacity_[arc], upper_bound);
195 min_node_excess[node] =
196 CapSub(min_node_excess[node], residual_arc_capacity_[arc]);
197 }
198 if (min_node_excess[node] > -kMaxFlow) continue;
199 }
200 if (min_node_excess[node] > -std::numeric_limits<ArcFlowType>::max()) {
201 // There is no point having an incoming arc with more than this.
202 const ArcFlowType upper_bound =
203 std::max<ArcFlowType>(0, -min_node_excess[node]);
204
205 // Adjust and recompute max_node_excess[node].
206 max_node_excess[node] = node_excess_[node];
207 for (IncomingArcIterator it(*graph_, node); it.Ok(); it.Next()) {
208 const int arc = it.Index();
209 residual_arc_capacity_[arc] =
210 std::min(residual_arc_capacity_[arc], upper_bound);
211 max_node_excess[node] =
212 CapAdd(max_node_excess[node], residual_arc_capacity_[arc]);
213 }
214 if (max_node_excess[node] < kMaxFlow) continue;
215 }
216
217 status_ = BAD_CAPACITY_RANGE;
218 LOG(ERROR) << "Maximum in or out flow of node + excess " << node
219 << " overflow the FlowQuantity type (int64_t).";
220 return false;
221 }
222 }
223 return true;
224}
225
226template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
227bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::CheckResult()
228 const {
229 for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
230 if (node_excess_[node] != 0) {
231 LOG(DFATAL) << "node_excess_[" << node << "] != 0";
232 return false;
233 }
234 for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
235 it.Next()) {
236 const ArcIndex arc = it.Index();
237 bool ok = true;
238 if (residual_arc_capacity_[arc] < 0) {
239 LOG(DFATAL) << "residual_arc_capacity_[" << arc << "] < 0";
240 ok = false;
241 }
242 if (residual_arc_capacity_[arc] > 0 && ReducedCost(arc) < -epsilon_) {
243 LOG(DFATAL) << "residual_arc_capacity_[" << arc
244 << "] > 0 && ReducedCost(" << arc << ") < " << -epsilon_
245 << ". (epsilon_ = " << epsilon_ << ").";
246 ok = false;
247 }
248 if (!ok) {
249 LOG(DFATAL) << DebugString("CheckResult ", arc);
250 return false;
251 }
252 }
253 }
254 return true;
255}
256
257template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
260 // Note that the classical Relabel precondition assumes IsActive(node), i.e.,
261 // the node_excess_[node] > 0. However, to implement the Push Look-Ahead
262 // heuristic, we can relax this condition as explained in the section 4.3 of
263 // the article "An Efficient Implementation of a Scaling Minimum-Cost Flow
264 // Algorithm", A.V. Goldberg, Journal of Algorithms 22(1), January 1997, pp.
265 // 1-29.
266 DCHECK_GE(node_excess_[node], 0);
267 for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
268 it.Next()) {
269 const ArcIndex arc = it.Index();
270 DCHECK(!IsAdmissible(arc)) << DebugString("CheckRelabelPrecondition:", arc);
271 }
272 return true;
273}
274
275template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
276std::string
277GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::DebugString(
278 absl::string_view context, ArcIndex arc) const {
279 const NodeIndex tail = Tail(arc);
280 const NodeIndex head = Head(arc);
281 // Reduced cost is computed directly without calling ReducedCost to avoid
282 // recursive calls between ReducedCost and DebugString in case a DCHECK in
283 // ReducedCost fails.
284 const CostValue reduced_cost = scaled_arc_unit_cost_[arc] +
285 node_potential_[tail] - node_potential_[head];
286 return absl::StrFormat(
287 "%s Arc %d, from %d to %d, "
288 "Capacity = %d, Residual capacity = %d, "
289 "Flow = residual capacity for reverse arc = %d, "
290 "Height(tail) = %d, Height(head) = %d, "
291 "Excess(tail) = %d, Excess(head) = %d, "
292 "Cost = %d, Reduced cost = %d, ",
293 context, arc, tail, head, Capacity(arc),
294 static_cast<FlowQuantity>(residual_arc_capacity_[arc]), Flow(arc),
295 node_potential_[tail], node_potential_[head], node_excess_[tail],
296 node_excess_[head], static_cast<CostValue>(scaled_arc_unit_cost_[arc]),
297 reduced_cost);
298}
299
300template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
301bool GenericMinCostFlow<Graph, ArcFlowType,
302 ArcScaledCostType>::CheckFeasibility() {
303 SCOPED_TIME_STAT(&stats_);
304 // Create a new graph, which is a copy of graph_, with the following
305 // modifications:
306 // Two nodes are added: a source and a sink.
307 // The source is linked to each supply node (whose supply > 0) by an arc whose
308 // capacity is equal to the supply at the supply node.
309 // The sink is linked to each demand node (whose supply < 0) by an arc whose
310 // capacity is the demand (-supply) at the demand node.
311 // There are no supplies or demands or costs in the graph, as we will run
312 // max-flow.
313 // TODO(user): make it possible to share a graph by MaxFlow and MinCostFlow.
314 feasibility_checked_ = false;
315 ArcIndex num_extra_arcs = 0;
316 for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
317 if (initial_node_excess_[node] != 0) {
318 ++num_extra_arcs;
319 }
320 }
321 const NodeIndex num_nodes_in_max_flow = graph_->num_nodes() + 2;
322 const ArcIndex num_arcs_in_max_flow = graph_->num_arcs() + num_extra_arcs;
323 const NodeIndex source = num_nodes_in_max_flow - 2;
324 const NodeIndex sink = num_nodes_in_max_flow - 1;
325 using CheckerGraph = ::util::ReverseArcListGraph<>;
326 CheckerGraph checker_graph(num_nodes_in_max_flow, num_arcs_in_max_flow);
327 GenericMaxFlow<CheckerGraph> checker(&checker_graph, source, sink);
328 // Copy graph_ to checker_graph.
329 for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
330 const ArcIndex new_arc =
331 checker_graph.AddArc(graph_->Tail(arc), graph_->Head(arc));
332 DCHECK_EQ(arc, new_arc);
333 checker.SetArcCapacity(new_arc, Capacity(arc));
334 }
335 FlowQuantity total_demand = 0;
336 FlowQuantity total_supply = 0;
337 // Create the source-to-supply node arcs and the demand-node-to-sink arcs.
338 for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
339 const FlowQuantity supply = initial_node_excess_[node];
340 if (supply > 0) {
341 const ArcIndex new_arc = checker_graph.AddArc(source, node);
342 checker.SetArcCapacity(new_arc, supply);
343 total_supply += supply;
344 } else if (supply < 0) {
345 const ArcIndex new_arc = checker_graph.AddArc(node, sink);
346 checker.SetArcCapacity(new_arc, -supply);
347 total_demand -= supply;
348 }
349 }
350 if (total_supply != total_demand) {
351 LOG(DFATAL) << "total_supply(" << total_supply << ") != total_demand("
352 << total_demand << ").";
353 return false;
354 }
355 if (!checker.Solve()) {
356 LOG(DFATAL) << "Max flow could not be computed.";
357 return false;
358 }
359 const FlowQuantity optimal_max_flow = checker.GetOptimalFlow();
360 feasibility_checked_ = true;
361 return optimal_max_flow == total_supply;
362}
363
364template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
366 ArcIndex arc) const -> FlowQuantity {
367 if (IsArcDirect(arc)) {
368 return residual_arc_capacity_[Opposite(arc)];
369 } else {
370 return -residual_arc_capacity_[arc];
371 }
372}
373
374// We use the equations given in the comment of residual_arc_capacity_.
375template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
377 ArcIndex arc) const -> FlowQuantity {
378 if (IsArcDirect(arc)) {
379 return residual_arc_capacity_[arc] + residual_arc_capacity_[Opposite(arc)];
380 } else {
381 return 0;
382 }
383}
384
385template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
387 ArcIndex arc) const -> CostValue {
388 DCHECK(IsArcValid(arc));
389 DCHECK_EQ(uint64_t{1}, cost_scaling_factor_);
390 return scaled_arc_unit_cost_[arc];
391}
392
393template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
395 NodeIndex node) const -> FlowQuantity {
396 DCHECK(graph_->IsNodeValid(node));
397 return node_excess_[node];
398}
399
400template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
401bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::IsAdmissible(
402 ArcIndex arc) const {
403 return FastIsAdmissible(arc, node_potential_[Tail(arc)]);
404}
405
406template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
407bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::
408 FastIsAdmissible(ArcIndex arc, CostValue tail_potential) const {
409 DCHECK_EQ(node_potential_[Tail(arc)], tail_potential);
410 return residual_arc_capacity_[arc] > 0 &&
411 FastReducedCost(arc, tail_potential) < 0;
412}
413
414template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
415bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::IsActive(
416 NodeIndex node) const {
417 return node_excess_[node] > 0;
418}
419
420template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
421auto GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::ReducedCost(
422 ArcIndex arc) const -> CostValue {
423 return FastReducedCost(arc, node_potential_[Tail(arc)]);
424}
425
426template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
427auto GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::FastReducedCost(
428 ArcIndex arc, CostValue tail_potential) const -> CostValue {
429 DCHECK_EQ(node_potential_[Tail(arc)], tail_potential);
430 DCHECK(graph_->IsNodeValid(Tail(arc)));
431 DCHECK(graph_->IsNodeValid(Head(arc)));
432 DCHECK_LE(node_potential_[Tail(arc)], 0) << DebugString("ReducedCost:", arc);
433 DCHECK_LE(node_potential_[Head(arc)], 0) << DebugString("ReducedCost:", arc);
434
435 // Note that there should be no overflow independently of the order of
436 // operations if potentials are in [overflow_threshold_, 0].
437 return scaled_arc_unit_cost_[arc] + tail_potential -
438 node_potential_[Head(arc)];
439}
440
441template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
444 OutgoingOrOppositeIncomingArcIterator arc_it(*graph_, node);
445 return arc_it.Index();
446}
447
448template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
450 if (!CheckInputConsistency()) {
451 return false;
452 }
453 if (check_feasibility_ && !CheckFeasibility()) {
454 status_ = INFEASIBLE;
455 return false;
456 }
457
458 status_ = NOT_SOLVED;
459 node_potential_.assign(node_potential_.size(), 0);
460
461 ResetFirstAdmissibleArcs();
462 if (!ScaleCosts()) return false;
463 if (!Optimize()) return false;
464 DCHECK_EQ(status_, NOT_SOLVED);
465 status_ = OPTIMAL;
466
467 if (absl::GetFlag(FLAGS_min_cost_flow_check_result) && !CheckResult()) {
468 status_ = BAD_RESULT;
469 UnscaleCosts();
470 return false;
471 }
472 UnscaleCosts();
473
474 IF_STATS_ENABLED(VLOG(1) << stats_.StatString());
475 return true;
476}
477
478template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
480 -> CostValue {
481 if (status_ != OPTIMAL) {
482 return 0;
483 }
484
485 // The total cost of the flow.
486 // We cap the result if its overflow.
487 CostValue total_flow_cost = 0;
488 const CostValue kMaxCost = std::numeric_limits<CostValue>::max();
489 const CostValue kMinCost = std::numeric_limits<CostValue>::min();
490 for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
491 const CostValue flow_on_arc = residual_arc_capacity_[Opposite(arc)];
492 const CostValue flow_cost =
493 CapProd(scaled_arc_unit_cost_[arc], flow_on_arc);
494 if (flow_cost == kMaxCost || flow_cost == kMinCost) return kMaxCost;
495 total_flow_cost = CapAdd(flow_cost, total_flow_cost);
496 if (total_flow_cost == kMaxCost || total_flow_cost == kMinCost) {
497 return kMaxCost;
498 }
499 }
500 return total_flow_cost;
501}
502
503template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
504void GenericMinCostFlow<Graph, ArcFlowType,
505 ArcScaledCostType>::ResetFirstAdmissibleArcs() {
506 for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
507 first_admissible_arc_[node] = GetFirstOutgoingOrOppositeIncomingArc(node);
508 }
509}
510
511template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
512bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::ScaleCosts() {
513 SCOPED_TIME_STAT(&stats_);
514 cost_scaling_factor_ = scale_prices_ ? graph_->num_nodes() + 1 : 1;
515 epsilon_ = 1LL;
516 VLOG(3) << "Number of nodes in the graph = " << graph_->num_nodes();
517 VLOG(3) << "Number of arcs in the graph = " << graph_->num_arcs();
518 const CostValue threshold =
519 std::numeric_limits<CostValue>::max() / (2 * cost_scaling_factor_);
520 for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
521 if (scaled_arc_unit_cost_[arc] > threshold ||
522 scaled_arc_unit_cost_[arc] < -threshold) {
523 status_ = BAD_COST_RANGE;
524 return false;
525 }
526 const CostValue cost = scaled_arc_unit_cost_[arc] * cost_scaling_factor_;
527 scaled_arc_unit_cost_.Set(arc, cost);
528 scaled_arc_unit_cost_.Set(Opposite(arc), -cost);
529 epsilon_ = std::max(epsilon_, MathUtil::Abs(cost));
530 }
531
532 // Since epsilon_ is currently the largest scaled cost, as long as our
533 // node potentials stay above this threshold, we can correctly compute
534 // potential - epsilon or cost + potential_diff.
535 overflow_threshold_ = std::numeric_limits<CostValue>::min() + epsilon_;
536
537 VLOG(3) << "Initial epsilon = " << epsilon_;
538 VLOG(3) << "Cost scaling factor = " << cost_scaling_factor_;
539 return true;
540}
541
542template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
543void GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::UnscaleCosts() {
544 SCOPED_TIME_STAT(&stats_);
545 for (ArcIndex arc = 0; arc < graph_->num_arcs(); ++arc) {
546 const CostValue cost = scaled_arc_unit_cost_[arc] / cost_scaling_factor_;
547 scaled_arc_unit_cost_.Set(arc, cost);
548 scaled_arc_unit_cost_.Set(Opposite(arc), -cost);
549 }
550 cost_scaling_factor_ = 1;
551}
552
553template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
554bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::Optimize() {
555 const CostValue kEpsilonMin = 1LL;
556 num_relabels_since_last_price_update_ = 0;
557 do {
558 // Avoid epsilon_ == 0.
559 epsilon_ = std::max(epsilon_ / alpha_, kEpsilonMin);
560 VLOG(3) << "Epsilon changed to: " << epsilon_;
561 if (!Refine()) return false;
562 } while (epsilon_ != 1LL);
563 return true;
564}
565
566template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
567void GenericMinCostFlow<Graph, ArcFlowType,
568 ArcScaledCostType>::SaturateAdmissibleArcs() {
569 SCOPED_TIME_STAT(&stats_);
570 for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
571 const CostValue tail_potential = node_potential_[node];
572 for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node,
573 first_admissible_arc_[node]);
574 it.Ok(); it.Next()) {
575 const ArcIndex arc = it.Index();
576 if (FastIsAdmissible(arc, tail_potential)) {
577 FastPushFlow(residual_arc_capacity_[arc], arc, node);
578 }
579 }
580
581 // We just saturated all the admissible arcs, so there are no arcs with a
582 // positive residual capacity that are incident to the current node.
583 // Moreover, during the course of the algorithm, if the residual capacity of
584 // such an arc becomes positive again, then the arc is still not admissible
585 // until we relabel the node (because the reverse arc was admissible for
586 // this to happen). In conclusion, the optimization below is correct.
587 first_admissible_arc_[node] = Graph::kNilArc;
588 }
589}
590
591template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
592void GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::PushFlow(
593 FlowQuantity flow, ArcIndex arc) {
594 SCOPED_TIME_STAT(&stats_);
595 FastPushFlow(flow, arc, Tail(arc));
596}
597
598template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
599void GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::FastPushFlow(
600 FlowQuantity flow, ArcIndex arc, NodeIndex tail) {
601 SCOPED_TIME_STAT(&stats_);
602 DCHECK_EQ(Tail(arc), tail);
603 DCHECK_GT(residual_arc_capacity_[arc], 0);
604 DCHECK_LE(flow, residual_arc_capacity_[arc]);
605 // Reduce the residual capacity on the arc by flow.
606 residual_arc_capacity_.Set(arc, residual_arc_capacity_[arc] - flow);
607 // Increase the residual capacity on the opposite arc by flow.
608 const ArcIndex opposite = Opposite(arc);
609 residual_arc_capacity_.Set(opposite, residual_arc_capacity_[opposite] + flow);
610 // Update the excesses at the tail and head of the arc.
611 node_excess_[tail] -= flow;
612 node_excess_[Head(arc)] += flow;
613}
614
615template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
616void GenericMinCostFlow<Graph, ArcFlowType,
617 ArcScaledCostType>::InitializeActiveNodeStack() {
618 SCOPED_TIME_STAT(&stats_);
619 DCHECK(active_nodes_.empty());
620 for (NodeIndex node = 0; node < graph_->num_nodes(); ++node) {
621 if (IsActive(node)) {
622 active_nodes_.push(node);
623 }
624 }
625}
626
627template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
628bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::UpdatePrices() {
629 SCOPED_TIME_STAT(&stats_);
630
631 // The algorithm works as follows. Start with a set of nodes S containing all
632 // the nodes with negative excess. Expand the set along reverse admissible
633 // arcs. If at the end, the complement of S contains at least one node with
634 // positive excess, relabel all the nodes in the complement of S by
635 // subtracting epsilon from their current potential. See the paper cited in
636 // the .h file.
637 //
638 // After this relabeling is done, the heuristic is reapplied by extending S as
639 // much as possible, relabeling the complement of S, and so on until there is
640 // no node with positive excess that is not in S. Note that this is not
641 // described in the paper.
642 //
643 // Note(user): The triggering mechanism of this UpdatePrices() is really
644 // important; if it is not done properly it may degrade performance!
645
646 // This represents the set S.
647 const NodeIndex num_nodes = graph_->num_nodes();
648 std::vector<NodeIndex> bfs_queue;
649 std::vector<bool> node_in_queue(num_nodes, false);
650
651 // This is used to update the potential of the nodes not in S.
652 const CostValue kMinCostValue = std::numeric_limits<CostValue>::min();
653 std::vector<CostValue> min_non_admissible_potential(num_nodes, kMinCostValue);
654 std::vector<NodeIndex> nodes_to_process;
655
656 // Sum of the positive excesses out of S, used for early exit.
657 FlowQuantity remaining_excess = 0;
658
659 // First consider the nodes which have a negative excess.
660 for (NodeIndex node = 0; node < num_nodes; ++node) {
661 if (node_excess_[node] < 0) {
662 bfs_queue.push_back(node);
663 node_in_queue[node] = true;
664
665 // This uses the fact that the sum of excesses is always 0.
666 remaining_excess -= node_excess_[node];
667 }
668 }
669
670 // All the nodes not yet in the bfs_queue will have their potential changed by
671 // +potential_delta (which becomes more and more negative at each pass). This
672 // update is applied when a node is pushed into the queue and at the end of
673 // the function for the nodes that are still unprocessed.
674 CostValue potential_delta = 0;
675
676 int queue_index = 0;
677 while (remaining_excess > 0) {
678 // Reverse BFS that expands S as much as possible in the reverse admissible
679 // graph. Once S cannot be expanded anymore, perform a relabeling on the
680 // nodes not in S but that can reach it in one arc and try to expand S
681 // again.
682 for (; queue_index < bfs_queue.size(); ++queue_index) {
683 DCHECK_GE(num_nodes, bfs_queue.size());
684 const NodeIndex node = bfs_queue[queue_index];
685 for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
686 it.Next()) {
687 const NodeIndex head = Head(it.Index());
688 if (node_in_queue[head]) continue;
689 const ArcIndex opposite_arc = Opposite(it.Index());
690 if (residual_arc_capacity_[opposite_arc] > 0) {
691 node_potential_[head] += potential_delta;
692 if (node_potential_[head] < overflow_threshold_) {
693 status_ = BAD_COST_RANGE;
694 return false;
695 }
696 if (ReducedCost(opposite_arc) < 0) {
697 DCHECK(IsAdmissible(opposite_arc));
698
699 // TODO(user): Try to steal flow if node_excess_[head] > 0.
700 // An initial experiment didn't show a big speedup though.
701
702 remaining_excess -= node_excess_[head];
703 if (remaining_excess == 0) {
704 node_potential_[head] -= potential_delta;
705 break;
706 }
707 bfs_queue.push_back(head);
708 node_in_queue[head] = true;
709 if (potential_delta < 0) {
710 first_admissible_arc_[head] =
711 GetFirstOutgoingOrOppositeIncomingArc(head);
712 }
713 } else {
714 // The opposite_arc is not admissible but is in the residual graph;
715 // this updates its min_non_admissible_potential.
716 node_potential_[head] -= potential_delta;
717 if (min_non_admissible_potential[head] == kMinCostValue) {
718 nodes_to_process.push_back(head);
719 }
720 min_non_admissible_potential[head] = std::max(
721 min_non_admissible_potential[head],
722 node_potential_[node] - scaled_arc_unit_cost_[opposite_arc]);
723 }
724 }
725 }
726 if (remaining_excess == 0) break;
727 }
728 if (remaining_excess == 0) break;
729
730 // Decrease by as much as possible instead of decreasing by epsilon.
731 // TODO(user): Is it worth the extra loop?
732 CostValue max_potential_diff = kMinCostValue;
733 for (int i = 0; i < nodes_to_process.size(); ++i) {
734 const NodeIndex node = nodes_to_process[i];
735 if (node_in_queue[node]) continue;
736 max_potential_diff =
737 std::max(max_potential_diff,
738 min_non_admissible_potential[node] - node_potential_[node]);
739 if (max_potential_diff == potential_delta) break;
740 }
741 DCHECK_LE(max_potential_diff, potential_delta);
742 potential_delta = max_potential_diff - epsilon_;
743
744 // Loop over nodes_to_process_ and for each node, apply the first of the
745 // rules below that match or leave it in the queue for later iteration:
746 // - Remove it if it is already in the queue.
747 // - If the node is connected to S by an admissible arc after it is
748 // relabeled by +potential_delta, add it to bfs_queue_ and remove it from
749 // nodes_to_process.
750 int index = 0;
751 for (int i = 0; i < nodes_to_process.size(); ++i) {
752 const NodeIndex node = nodes_to_process[i];
753 if (node_in_queue[node]) continue;
754 if (node_potential_[node] + potential_delta <
755 min_non_admissible_potential[node]) {
756 node_potential_[node] += potential_delta;
757 if (node_potential_[node] < overflow_threshold_) {
758 status_ = BAD_COST_RANGE;
759 return false;
760 }
761 first_admissible_arc_[node] =
762 GetFirstOutgoingOrOppositeIncomingArc(node);
763 bfs_queue.push_back(node);
764 node_in_queue[node] = true;
765 remaining_excess -= node_excess_[node];
766 continue;
767 }
768
769 // Keep the node for later iteration.
770 nodes_to_process[index] = node;
771 ++index;
772 }
773 nodes_to_process.resize(index);
774 }
775
776 // Update the potentials of the nodes not yet processed.
777 if (potential_delta == 0) return true;
778 for (NodeIndex node = 0; node < num_nodes; ++node) {
779 if (!node_in_queue[node]) {
780 node_potential_[node] += potential_delta;
781 if (node_potential_[node] < overflow_threshold_) {
782 status_ = BAD_COST_RANGE;
783 return false;
784 }
785 first_admissible_arc_[node] = GetFirstOutgoingOrOppositeIncomingArc(node);
786 }
787 }
788 return true;
789}
790
791template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
792bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::Refine() {
793 SCOPED_TIME_STAT(&stats_);
794 SaturateAdmissibleArcs();
795 InitializeActiveNodeStack();
796
797 const NodeIndex num_nodes = graph_->num_nodes();
798 while (!active_nodes_.empty()) {
799 // TODO(user): Experiment with different factors in front of num_nodes.
800 if (num_relabels_since_last_price_update_ >= num_nodes) {
801 num_relabels_since_last_price_update_ = 0;
802 if (use_price_update_) {
803 if (!UpdatePrices()) return false;
804 }
805 }
806 const NodeIndex node = active_nodes_.top();
807 active_nodes_.pop();
808 DCHECK(IsActive(node));
809 if (!Discharge(node)) return false;
810 }
811 return true;
812}
813
814template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
815bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::Discharge(
816 NodeIndex node) {
817 SCOPED_TIME_STAT(&stats_);
818 while (true) {
819 // The node is initially active, and we exit as soon as it becomes
820 // inactive.
821 DCHECK(IsActive(node));
822 const CostValue tail_potential = node_potential_[node];
823 for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node,
824 first_admissible_arc_[node]);
825 it.Ok(); it.Next()) {
826 const ArcIndex arc = it.Index();
827 if (!FastIsAdmissible(arc, tail_potential)) continue;
828
829 // We look ahead to see if this node can accept the flow or will need
830 // to be relabeled later in which case we do it now. Note that this will
831 // just be skipped for self-loop so it is fine.
832 const NodeIndex head = Head(arc);
833 if (node_excess_[head] >= 0 && !NodeHasAdmissibleArc(head)) {
834 // Relabel head and skip if the arc is not admissible anymore.
835 if (!Relabel(head)) return false;
836 if (!FastIsAdmissible(arc, tail_potential)) continue;
837 }
838
839 const FlowQuantity delta =
840 std::min(node_excess_[node],
841 static_cast<FlowQuantity>(residual_arc_capacity_[arc]));
842 const bool head_active_before_push = IsActive(head);
843 FastPushFlow(delta, arc, node);
844 if (IsActive(head) && !head_active_before_push) {
845 active_nodes_.push(head);
846 }
847
848 if (node_excess_[node] == 0) {
849 // arc may still be admissible.
850 first_admissible_arc_[node] = arc;
851 return true;
852 }
853 }
854 if (!Relabel(node)) return false;
855 }
856}
857
858template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
861 SCOPED_TIME_STAT(&stats_);
862 const CostValue tail_potential = node_potential_[node];
863 for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node,
864 first_admissible_arc_[node]);
865 it.Ok(); it.Next()) {
866 const ArcIndex arc = it.Index();
867 if (FastIsAdmissible(arc, tail_potential)) {
868 first_admissible_arc_[node] = arc;
869 return true;
870 }
871 }
872 return false;
873}
874
875// Note that we only relabel if there is no leaving admissible arc.
876template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
877bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::Relabel(
878 NodeIndex node) {
879 SCOPED_TIME_STAT(&stats_);
880 DCHECK(CheckRelabelPrecondition(node));
881 ++num_relabels_since_last_price_update_;
882
883 // By setting node_potential_[node] to the guaranteed_new_potential we are
884 // sure to keep epsilon-optimality of the pseudo-flow. Note that we could
885 // return right away with this value, but we prefer to check that this value
886 // will lead to at least one admissible arc, and if not, to decrease the
887 // potential as much as possible.
888 const CostValue guaranteed_new_potential = node_potential_[node] - epsilon_;
889 if (guaranteed_new_potential < overflow_threshold_) {
890 status_ = BAD_COST_RANGE;
891 return false;
892 }
893
894 // This will be updated to contain the minimum node potential for which
895 // the node has no admissible arc. We know that:
896 // - min_non_admissible_potential <= node_potential_[node]
897 // - We can set the new node potential to min_non_admissible_potential -
898 // epsilon_ and still keep the epsilon-optimality of the pseudo flow.
899 const CostValue kMinCostValue = std::numeric_limits<CostValue>::min();
900 CostValue min_non_admissible_potential = kMinCostValue;
901
902 // The following variables help setting the first_admissible_arc_[node] to a
903 // value different from GetFirstOutgoingOrOppositeIncomingArc(node) which
904 // avoids looking again at some arcs.
905 CostValue previous_min_non_admissible_potential = kMinCostValue;
906 ArcIndex first_arc = Graph::kNilArc;
907
908 for (OutgoingOrOppositeIncomingArcIterator it(*graph_, node); it.Ok();
909 it.Next()) {
910 const ArcIndex arc = it.Index();
911 if (residual_arc_capacity_[arc] > 0) {
912 const CostValue min_non_admissible_potential_for_arc =
913 node_potential_[Head(arc)] - scaled_arc_unit_cost_[arc];
914 // We test this condition first as it is more probable that the first arc
915 // with residual capacity will be admissible if we reduce the node
916 // potential by epsilon.
917 if (min_non_admissible_potential_for_arc > guaranteed_new_potential) {
918 // We found an admissible arc for the guaranteed_new_potential. We
919 // stop right now instead of trying to compute the minimum possible
920 // new potential that keeps the epsilon-optimality of the pseudo flow.
921 node_potential_[node] = guaranteed_new_potential;
922 first_admissible_arc_[node] = arc;
923 return true;
924 }
925 if (min_non_admissible_potential_for_arc > min_non_admissible_potential) {
926 previous_min_non_admissible_potential = min_non_admissible_potential;
927 min_non_admissible_potential = min_non_admissible_potential_for_arc;
928 first_arc = arc;
929 }
930 }
931 }
932
933 // No residual arc leaves this node!
934 //
935 // TODO(user): This can be dealt with before the aglorithm start so that we
936 // do not need to test it here.
937 if (min_non_admissible_potential == kMinCostValue) {
938 if (node_excess_[node] != 0) {
939 // Note that this infeasibility detection is incomplete.
940 // Only max flow can detect that a min-cost flow problem is infeasible.
941 status_ = INFEASIBLE;
942 return false;
943 } else {
944 // This source saturates all its arcs, we can actually decrease the
945 // potential by as much as we want.
946 //
947 // TODO(user): Set it to a minimum value? but be careful of overflow.
948 node_potential_[node] = guaranteed_new_potential;
949 first_admissible_arc_[node] = Graph::kNilArc;
950 }
951 return true;
952 }
953
954 // We decrease the potential as much as possible, but we do not know the first
955 // admissible arc (most of the time). Keeping the
956 // previous_min_non_admissible_potential makes it faster by a few percent.
957 if (min_non_admissible_potential < overflow_threshold_) {
958 status_ = BAD_COST_RANGE;
959 return false;
960 }
961 const CostValue new_potential = min_non_admissible_potential - epsilon_;
962 if (new_potential < overflow_threshold_) {
963 status_ = BAD_COST_RANGE;
964 return false;
965 }
966 node_potential_[node] = new_potential;
967 if (previous_min_non_admissible_potential <= new_potential) {
968 first_admissible_arc_[node] = first_arc;
969 } else {
970 // We have no indication of what may be the first admissible arc.
971 first_admissible_arc_[node] = GetFirstOutgoingOrOppositeIncomingArc(node);
972 }
973 return true;
974}
975
976template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
977typename Graph::ArcIndex
978GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::Opposite(
979 ArcIndex arc) const {
980 return graph_->OppositeArc(arc);
981}
982
983template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
984bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::IsArcValid(
985 ArcIndex arc) const {
986 return graph_->IsArcValid(arc);
987}
988
989template <typename Graph, typename ArcFlowType, typename ArcScaledCostType>
990bool GenericMinCostFlow<Graph, ArcFlowType, ArcScaledCostType>::IsArcDirect(
991 ArcIndex arc) const {
992 DCHECK(IsArcValid(arc));
993 return arc >= 0;
994}
995
996// Explicit instantiations that can be used by a client.
997//
998// TODO(user): Move this code out of a .cc file and include it at the end of
999// the header so it can work with any graph implementation?
1003template class GenericMinCostFlow<
1004 ::util::ReverseArcStaticGraph<uint16_t, int32_t>>;
1006 int64_t, int64_t>;
1007
1008// A more memory-efficient version for large graphs.
1009template class GenericMinCostFlow<
1010 ::util::ReverseArcStaticGraph<uint16_t, int32_t>,
1011 /*ArcFlowType=*/int16_t,
1012 /*ArcScaledCostType=*/int32_t>;
1013
1015 ArcIndex reserve_num_arcs) {
1016 if (reserve_num_nodes > 0) {
1017 node_supply_.reserve(reserve_num_nodes);
1018 }
1019 if (reserve_num_arcs > 0) {
1020 arc_tail_.reserve(reserve_num_arcs);
1021 arc_head_.reserve(reserve_num_arcs);
1022 arc_capacity_.reserve(reserve_num_arcs);
1023 arc_cost_.reserve(reserve_num_arcs);
1024 arc_permutation_.reserve(reserve_num_arcs);
1025 arc_flow_.reserve(reserve_num_arcs);
1026 }
1027}
1028
1030 ResizeNodeVectors(node);
1031 node_supply_[node] = supply;
1032}
1033
1035 NodeIndex tail, NodeIndex head, FlowQuantity capacity,
1036 CostValue unit_cost) {
1037 ResizeNodeVectors(std::max(tail, head));
1038 const ArcIndex arc = arc_tail_.size();
1039 arc_tail_.push_back(tail);
1040 arc_head_.push_back(head);
1041 arc_capacity_.push_back(capacity);
1042 arc_cost_.push_back(unit_cost);
1043 return arc;
1044}
1045
1047 arc_capacity_[arc] = capacity;
1048}
1049
1050SimpleMinCostFlow::ArcIndex SimpleMinCostFlow::PermutedArc(ArcIndex arc) {
1051 return arc < arc_permutation_.size() ? arc_permutation_[arc] : arc;
1052}
1053
1054SimpleMinCostFlow::Status SimpleMinCostFlow::SolveWithPossibleAdjustment(
1055 SupplyAdjustment adjustment) {
1056 optimal_cost_ = 0;
1057 maximum_flow_ = 0;
1058 arc_flow_.clear();
1059 const NodeIndex num_nodes = node_supply_.size();
1060 const ArcIndex num_arcs = arc_capacity_.size();
1061 if (num_nodes == 0) return OPTIMAL;
1062
1063 int supply_node_count = 0, demand_node_count = 0;
1064 FlowQuantity total_supply = 0, total_demand = 0;
1065 for (NodeIndex node = 0; node < num_nodes; ++node) {
1066 if (node_supply_[node] > 0) {
1067 ++supply_node_count;
1068 total_supply += node_supply_[node];
1069 } else if (node_supply_[node] < 0) {
1070 ++demand_node_count;
1071 total_demand -= node_supply_[node];
1072 }
1073 }
1074 if (adjustment == DONT_ADJUST && total_supply != total_demand) {
1075 return UNBALANCED;
1076 }
1077
1078 // Feasibility checking, and possible supply/demand adjustment, is done by:
1079 // 1. Creating a new source and sink node.
1080 // 2. Taking all nodes that have a non-zero supply or demand and
1081 // connecting them to the source or sink respectively. The arc thus
1082 // added has a capacity of the supply or demand.
1083 // 3. Computing the max flow between the new source and sink.
1084 // 4. If adjustment isn't being done, checking that the max flow is equal
1085 // to the total supply/demand (and returning INFEASIBLE if it isn't).
1086 // 5. Running min-cost max-flow on this augmented graph, using the max
1087 // flow computed in step 3 as the supply of the source and demand of
1088 // the sink.
1089 const ArcIndex augmented_num_arcs =
1090 num_arcs + supply_node_count + demand_node_count;
1091 const NodeIndex source = num_nodes;
1092 const NodeIndex sink = num_nodes + 1;
1093 const NodeIndex augmented_num_nodes = num_nodes + 2;
1094
1095 Graph graph(augmented_num_nodes, augmented_num_arcs);
1096 for (ArcIndex arc = 0; arc < num_arcs; ++arc) {
1097 graph.AddArc(arc_tail_[arc], arc_head_[arc]);
1098 }
1099
1100 for (NodeIndex node = 0; node < num_nodes; ++node) {
1101 if (node_supply_[node] > 0) {
1102 graph.AddArc(source, node);
1103 } else if (node_supply_[node] < 0) {
1104 graph.AddArc(node, sink);
1105 }
1106 }
1107
1108 graph.Build(&arc_permutation_);
1109
1110 {
1111 GenericMaxFlow<Graph> max_flow(&graph, source, sink);
1112 ArcIndex arc;
1113 for (arc = 0; arc < num_arcs; ++arc) {
1114 max_flow.SetArcCapacity(PermutedArc(arc), arc_capacity_[arc]);
1115 }
1116 for (NodeIndex node = 0; node < num_nodes; ++node) {
1117 if (node_supply_[node] != 0) {
1118 max_flow.SetArcCapacity(PermutedArc(arc), std::abs(node_supply_[node]));
1119 ++arc;
1120 }
1121 }
1122 CHECK_EQ(arc, augmented_num_arcs);
1123 if (!max_flow.Solve()) {
1124 LOG(ERROR) << "Max flow could not be computed.";
1125 switch (max_flow.status()) {
1127 return NOT_SOLVED;
1129 LOG(ERROR)
1130 << "Max flow failed but claimed to have an optimal solution";
1131 ABSL_FALLTHROUGH_INTENDED;
1132 default:
1133 return BAD_RESULT;
1134 }
1135 }
1136 maximum_flow_ = max_flow.GetOptimalFlow();
1137 }
1138
1139 if (adjustment == DONT_ADJUST && maximum_flow_ != total_supply) {
1140 return INFEASIBLE;
1141 }
1142
1143 GenericMinCostFlow<Graph> min_cost_flow(&graph);
1144 ArcIndex arc;
1145 for (arc = 0; arc < num_arcs; ++arc) {
1146 ArcIndex permuted_arc = PermutedArc(arc);
1147 min_cost_flow.SetArcUnitCost(permuted_arc, arc_cost_[arc]);
1148 min_cost_flow.SetArcCapacity(permuted_arc, arc_capacity_[arc]);
1149 }
1150 for (NodeIndex node = 0; node < num_nodes; ++node) {
1151 if (node_supply_[node] != 0) {
1152 ArcIndex permuted_arc = PermutedArc(arc);
1153 min_cost_flow.SetArcCapacity(permuted_arc, std::abs(node_supply_[node]));
1154 min_cost_flow.SetArcUnitCost(permuted_arc, 0);
1155 ++arc;
1156 }
1157 }
1158 min_cost_flow.SetNodeSupply(source, maximum_flow_);
1159 min_cost_flow.SetNodeSupply(sink, -maximum_flow_);
1160 min_cost_flow.SetCheckFeasibility(false);
1161 min_cost_flow.SetPriceScaling(scale_prices_);
1162
1163 arc_flow_.resize(num_arcs);
1164 if (min_cost_flow.Solve()) {
1165 optimal_cost_ = min_cost_flow.GetOptimalCost();
1166 for (arc = 0; arc < num_arcs; ++arc) {
1167 arc_flow_[arc] = min_cost_flow.Flow(PermutedArc(arc));
1168 }
1169 }
1170
1171 return min_cost_flow.status();
1172}
1173
1175 return optimal_cost_;
1176}
1177
1179 return maximum_flow_;
1180}
1181
1183 return arc_flow_[arc];
1184}
1185
1186SimpleMinCostFlow::SimpleMinCostFlow::NodeIndex SimpleMinCostFlow::NumNodes()
1187 const {
1188 return node_supply_.size();
1189}
1190
1192 return arc_tail_.size();
1193}
1194
1196 return arc_tail_[arc];
1197}
1198
1200 return arc_head_[arc];
1201}
1202
1204 ArcIndex arc) const {
1205 return arc_capacity_[arc];
1206}
1207
1209 return arc_cost_[arc];
1210}
1211
1213 NodeIndex node) const {
1214 return node_supply_[node];
1215}
1216
1217void SimpleMinCostFlow::ResizeNodeVectors(NodeIndex node) {
1218 if (node < node_supply_.size()) return;
1219 node_supply_.resize(node + 1);
1220}
1221
1222} // namespace operations_research
FlowQuantity Flow(ArcIndex arc) const
void SetArcUnitCost(ArcIndex arc, ArcScaledCostType unit_cost)
Sets the unit cost for the given arc.
bool Solve()
Solves the problem, returning true if a min-cost flow could be found.
void SetArcCapacity(ArcIndex arc, ArcFlowType new_capacity)
Sets the capacity for the given arc.
void SetNodeSupply(NodeIndex node, FlowQuantity supply)
const Graph * graph() const
Returns the graph associated to the current object.
CostValue UnitCost(ArcIndex arc) const
Returns the unscaled cost for the given arc.
FlowQuantity Supply(NodeIndex node) const
FlowQuantity Capacity(ArcIndex arc) const
We use the equations given in the comment of residual_arc_capacity_.
static T Abs(const T x)
Definition mathutil.h:96
NodeIndex Tail(ArcIndex arc) const
void SetNodeSupply(NodeIndex node, FlowQuantity supply)
void SetArcCapacity(ArcIndex arc, FlowQuantity capacity)
FlowQuantity Flow(ArcIndex arc) const
FlowQuantity Capacity(ArcIndex arc) const
CostValue UnitCost(ArcIndex arc) const
ArcIndex AddArcWithCapacityAndUnitCost(NodeIndex tail, NodeIndex head, FlowQuantity capacity, CostValue unit_cost)
NodeIndex Head(ArcIndex arc) const
SimpleMinCostFlow(NodeIndex reserve_num_nodes=0, ArcIndex reserve_num_arcs=0)
FlowQuantity Supply(NodeIndex node) const
static constexpr bool kHasNegativeReverseArcs
Definition graph.h:201
ABSL_FLAG(int64_t, min_cost_flow_alpha, 5, "Divide factor for epsilon at each refine step.")
In SWIG mode, we don't want anything besides these top-level includes.
int64_t CapAdd(int64_t x, int64_t y)
int64_t CapSub(int64_t x, int64_t y)
int64_t CapProd(int64_t x, int64_t y)
util::ReverseArcStaticGraph Graph
Type of graph to use.
#define IF_STATS_ENABLED(instructions)
Definition stats.h:417
#define SCOPED_TIME_STAT(stats)
Definition stats.h:418