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