forked from google/or-tools
-
Notifications
You must be signed in to change notification settings - Fork 9
/
graph.h
2416 lines (2135 loc) · 86.6 KB
/
graph.h
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.
//
//
// This file defines a generic graph interface on which most algorithms can be
// built and provides a few efficient implementations with a fast construction
// time. Its design is based on the experience acquired by the Operations
// Research team in their various graph algorithm implementations.
//
// The main ideas are:
// - Graph nodes and arcs are represented by integers.
// - Node or arc annotations (weight, cost, ...) are not part of the graph
// class, they can be stored outside in one or more arrays and can be easily
// retrieved using a node or arc as an index.
//
// Terminology:
// - An arc of a graph is directed and going from a tail node to a head node.
// - Some implementations also store 'reverse' arcs and can be used for
// undirected graph or flow-like algorithm.
// - A node or arc index is 'valid' if it represents a node or arc of
// the graph. The validity ranges are always [0, num_nodes()) for nodes and
// [0, num_arcs()) for forward arcs. Reverse arcs are elements of
// [-num_arcs(), 0) and are also considered valid by the implementations that
// store them.
//
// Provided implementations:
// - ListGraph<> for the simplest api. Also aliased to util::Graph.
// - StaticGraph<> for performance, but require calling Build(), see below
// - CompleteGraph<> if you need a fully connected graph
// - CompleteBipartiteGraph<> if you need a fully connected bipartite graph
// - ReverseArcListGraph<> to add reverse arcs to ListGraph<>
// - ReverseArcStaticGraph<> to add reverse arcs to StaticGraph<>
// - ReverseArcMixedGraph<> for a smaller memory footprint
//
// Utility classes & functions:
// - Permute() to permute an array according to a given permutation.
// - SVector<> vector with index range [-size(), size()) for ReverseArcGraph.
//
// Basic usage:
// typedef ListGraph<> Graph; // Choose a graph implementation.
// Graph graph;
// for (...) {
// graph.AddArc(tail, head);
// }
// ...
// for (int node = 0; node < graph.num_nodes(); ++node) {
// for (const int arc : graph.OutgoingArcs(node)) {
// head = graph.Head(arc);
// tail = node; // or graph.Tail(arc) which is fast but not as much.
// }
// }
//
// Iteration over the arcs touching a node:
//
// - OutgoingArcs(node): All the forward arcs leaving the node.
// - IncomingArcs(node): All the forward arcs arriving at the node.
//
// And two more involved ones:
//
// - OutgoingOrOppositeIncomingArcs(node): This returns both the forward arcs
// leaving the node (i.e. OutgoingArcs(node)) and the reverse arcs leaving the
// node (i.e. the opposite arcs of the ones returned by IncomingArcs(node)).
// - OppositeIncomingArcs(node): This returns the reverse arcs leaving the node.
//
// Note on iteration efficiency: When re-indexing the arcs it is not possible to
// have both the outgoing arcs and the incoming ones form a consecutive range.
//
// It is however possible to do so for the outgoing arcs and the opposite
// incoming arcs. It is why the OutgoingOrOppositeIncomingArcs() and
// OutgoingArcs() iterations are more efficient than the IncomingArcs() one.
//
// If you know the graph size in advance, this already set the number of nodes,
// reserve space for the arcs and check in DEBUG mode that you don't go over the
// bounds:
// Graph graph(num_nodes, arc_capacity);
//
// Storing and using node annotations:
// vector<bool> is_visited(graph.num_nodes(), false);
// ...
// for (int node = 0; node < graph.num_nodes(); ++node) {
// if (!is_visited[node]) ...
// }
//
// Storing and using arc annotations:
// vector<int> weights;
// for (...) {
// graph.AddArc(tail, head);
// weights.push_back(arc_weight);
// }
// ...
// for (const int arc : graph.OutgoingArcs(node)) {
// ... weights[arc] ...;
// }
//
// More efficient version:
// typedef StaticGraph<> Graph;
// Graph graph(num_nodes, arc_capacity); // Optional, but help memory usage.
// vector<int> weights;
// weights.reserve(arc_capacity); // Optional, but help memory usage.
// for (...) {
// graph.AddArc(tail, head);
// weights.push_back(arc_weight);
// }
// ...
// vector<Graph::ArcIndex> permutation;
// graph.Build(&permutation); // A static graph must be Build() before usage.
// Permute(permutation, &weights); // Build() may permute the arc index.
// ...
//
// Encoding an undirected graph: If you don't need arc annotation, then the best
// is to add two arcs for each edge (one in each direction) to a directed graph.
// Otherwise you can do the following.
//
// typedef ReverseArc... Graph;
// Graph graph;
// for (...) {
// graph.AddArc(tail, head); // or graph.AddArc(head, tail) but not both.
// edge_annotations.push_back(value);
// }
// ...
// for (const Graph::NodeIndex node : graph.AllNodes()) {
// for (const Graph::ArcIndex arc :
// graph.OutgoingOrOppositeIncomingArcs(node)) {
// destination = graph.Head(arc);
// annotation = edge_annotations[arc < 0 ? graph.OppositeArc(arc) : arc];
// }
// }
//
// Note: The graphs are primarily designed to be constructed first and then used
// because it covers most of the use cases. It is possible to extend the
// interface with more dynamicity (like removing arcs), but this is not done at
// this point. Note that a "dynamic" implementation will break some assumptions
// we make on what node or arc are valid and also on the indices returned by
// AddArc(). Some arguments for simplifying the interface at the cost of
// dynamicity are:
//
// - It is always possible to construct a static graph from a dynamic one
// before calling a complex algo.
// - If you really need a dynamic graph, maybe it is better to compute a graph
// property incrementally rather than calling an algorithm that starts from
// scratch each time.
#ifndef UTIL_GRAPH_GRAPH_H_
#define UTIL_GRAPH_GRAPH_H_
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <iterator>
#include <limits>
#include <new>
#include <type_traits>
#include <vector>
#include "absl/base/port.h"
#include "absl/debugging/leak_check.h"
#include "absl/types/span.h"
#include "ortools/base/logging.h"
#include "ortools/base/macros.h"
#include "ortools/base/types.h"
#include "ortools/graph/iterators.h"
namespace util {
// Forward declaration.
template <typename T>
class SVector;
// Base class of all Graphs implemented here. The default value for the graph
// index types is int32_t since almost all graphs that fit into memory do not
// need bigger indices.
//
// Note: The type can be unsigned, except for the graphs with reverse arcs
// where the ArcIndexType must be signed, but not necessarily the NodeIndexType.
template <typename NodeIndexType = int32_t, typename ArcIndexType = int32_t,
bool HasReverseArcs = false>
class BaseGraph {
public:
// Typedef so you can use Graph::NodeIndex and Graph::ArcIndex to be generic
// but also to improve the readability of your code. We also recommend
// that you define a typedef ... Graph; for readability.
typedef NodeIndexType NodeIndex;
typedef ArcIndexType ArcIndex;
BaseGraph()
: num_nodes_(0),
node_capacity_(0),
num_arcs_(0),
arc_capacity_(0),
const_capacities_(false) {}
BaseGraph(const BaseGraph&) = default;
BaseGraph& operator=(const BaseGraph&) = default;
virtual ~BaseGraph() = default;
// Returns the number of valid nodes in the graph. Prefer using num_nodes():
// the size() API is here to make Graph and vector<vector<int>> more alike.
NodeIndexType num_nodes() const { return num_nodes_; }
NodeIndexType size() const { return num_nodes_; } // Prefer num_nodes().
// Returns the number of valid arcs in the graph.
ArcIndexType num_arcs() const { return num_arcs_; }
// Allows nice range-based for loop:
// for (const NodeIndex node : graph.AllNodes()) { ... }
// for (const ArcIndex arc : graph.AllForwardArcs()) { ... }
IntegerRange<NodeIndex> AllNodes() const;
IntegerRange<ArcIndex> AllForwardArcs() const;
// Returns true if the given node is a valid node of the graph.
bool IsNodeValid(NodeIndexType node) const {
return node >= 0 && node < num_nodes_;
}
// Returns true if the given arc is a valid arc of the graph.
// Note that the arc validity range changes for graph with reverse arcs.
bool IsArcValid(ArcIndexType arc) const {
return (HasReverseArcs ? -num_arcs_ : 0) <= arc && arc < num_arcs_;
}
// Capacity reserved for future nodes, always >= num_nodes_.
NodeIndexType node_capacity() const;
// Capacity reserved for future arcs, always >= num_arcs_.
ArcIndexType arc_capacity() const;
// Changes the graph capacities. The functions will fail in debug mode if:
// - const_capacities_ is true.
// - A valid node does not fall into the new node range.
// - A valid arc does not fall into the new arc range.
// In non-debug mode, const_capacities_ is ignored and nothing will happen
// if the new capacity value for the arcs or the nodes is too small.
virtual void ReserveNodes(NodeIndexType bound) {
DCHECK(!const_capacities_);
DCHECK_GE(bound, num_nodes_);
if (bound <= num_nodes_) return;
node_capacity_ = bound;
}
virtual void ReserveArcs(ArcIndexType bound) {
DCHECK(!const_capacities_);
DCHECK_GE(bound, num_arcs_);
if (bound <= num_arcs_) return;
arc_capacity_ = bound;
}
void Reserve(NodeIndexType node_capacity, ArcIndexType arc_capacity) {
ReserveNodes(node_capacity);
ReserveArcs(arc_capacity);
}
// FreezeCapacities() makes any future attempt to change the graph capacities
// crash in DEBUG mode.
void FreezeCapacities();
// Constants that will never be a valid node or arc.
// They are the maximum possible node and arc capacity.
static const NodeIndexType kNilNode;
static const ArcIndexType kNilArc;
// TODO(user): remove the public functions below. They are just here during
// the transition from the old ebert_graph api to this new graph api.
template <typename A, typename B>
void GroupForwardArcsByFunctor(const A& a, B* b) {
LOG(FATAL) << "Not supported";
}
ArcIndexType max_end_arc_index() const { return arc_capacity_; }
protected:
// Functions commented when defined because they are implementation details.
void ComputeCumulativeSum(std::vector<ArcIndexType>* v);
void BuildStartAndForwardHead(SVector<NodeIndexType>* head,
std::vector<ArcIndexType>* start,
std::vector<ArcIndexType>* permutation);
NodeIndexType num_nodes_;
NodeIndexType node_capacity_;
ArcIndexType num_arcs_;
ArcIndexType arc_capacity_;
bool const_capacities_;
};
// Basic graph implementation without reverse arc. This class also serves as a
// documentation for the generic graph interface (minus the part related to
// reverse arcs).
//
// This implementation uses a linked list and compared to StaticGraph:
// - Is a bit faster to construct (if the arcs are not ordered by tail).
// - Does not require calling Build().
// - Has slower outgoing arc iteration.
// - Uses more memory: ArcIndexType * node_capacity()
// + (ArcIndexType + NodeIndexType) * arc_capacity().
// - Has an efficient Tail() but need an extra NodeIndexType/arc memory for it.
// - Never changes the initial arc index returned by AddArc().
//
// All graphs should be -compatible, but we haven't tested that.
template <typename NodeIndexType = int32_t, typename ArcIndexType = int32_t>
class ListGraph : public BaseGraph<NodeIndexType, ArcIndexType, false> {
typedef BaseGraph<NodeIndexType, ArcIndexType, false> Base;
using Base::arc_capacity_;
using Base::const_capacities_;
using Base::node_capacity_;
using Base::num_arcs_;
using Base::num_nodes_;
public:
using Base::IsArcValid;
ListGraph() {}
// Reserve space for the graph at construction and do not allow it to grow
// beyond that, see FreezeCapacities(). This constructor also makes any nodes
// in [0, num_nodes) valid.
ListGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity) {
this->Reserve(num_nodes, arc_capacity);
this->FreezeCapacities();
this->AddNode(num_nodes - 1);
}
// If node is not a valid node, sets num_nodes_ to node + 1 so that the given
// node becomes valid. It will fail in DEBUG mode if the capacities are fixed
// and the new node is out of range.
void AddNode(NodeIndexType node);
// Adds an arc to the graph and returns its current index which will always
// be num_arcs() - 1. It will also automatically call AddNode(tail)
// and AddNode(head). It will fail in DEBUG mode if the capacities
// are fixed and this cause the graph to grow beyond them.
//
// Note: Self referencing arcs and duplicate arcs are supported.
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head);
// Some graph implementations need to be finalized with Build() before they
// can be used. After Build() is called, the arc indices (which had been the
// return values of previous AddArc() calls) may change: the new index of
// former arc #i will be stored in permutation[i] if #i is smaller than
// permutation.size() or will be unchanged otherwise. If you don't care about
// these, just call the simple no-output version Build().
//
// Note that some implementations become immutable after calling Build().
void Build() { Build(nullptr); }
void Build(std::vector<ArcIndexType>* permutation);
// Do not use directly.
class OutgoingArcIterator;
class OutgoingHeadIterator;
// Graph jargon: the "degree" of a node is its number of arcs. The out-degree
// is the number of outgoing arcs. The in-degree is the number of incoming
// arcs, and is only available for some graph implementations, below.
//
// ListGraph<>::OutDegree() works in O(degree).
ArcIndexType OutDegree(NodeIndexType node) const;
// Allows to iterate over the forward arcs that verify Tail(arc) == node.
// This is meant to be used as:
// for (const ArcIndex arc : graph.OutgoingArcs(node)) { ... }
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const;
// Advanced usage. Same as OutgoingArcs(), but allows to restart the iteration
// from an already known outgoing arc of the given node.
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
// This loops over the heads of the OutgoingArcs(node). It is just a more
// convenient way to achieve this. Moreover this interface is used by some
// graph algorithms.
BeginEndWrapper<OutgoingHeadIterator> operator[](NodeIndexType node) const;
// Returns the tail/head of a valid arc.
NodeIndexType Tail(ArcIndexType arc) const;
NodeIndexType Head(ArcIndexType arc) const;
void ReserveNodes(NodeIndexType bound) override;
void ReserveArcs(ArcIndexType bound) override;
private:
std::vector<ArcIndexType> start_;
std::vector<ArcIndexType> next_;
std::vector<NodeIndexType> head_;
std::vector<NodeIndexType> tail_;
};
// Most efficient implementation of a graph without reverse arcs:
// - Build() needs to be called after the arc and node have been added.
// - The graph is really compact memory wise:
// ArcIndexType * node_capacity() + 2 * NodeIndexType * arc_capacity(),
// but when Build() is called it uses a temporary extra space of
// ArcIndexType * arc_capacity().
// - The construction is really fast.
//
// NOTE(user): if the need arises for very-well compressed graphs, we could
// shave NodeIndexType * arc_capacity() off the permanent memory requirement
// with a similar class that doesn't support Tail(), i.e.
// StaticGraphWithoutTail<>. This almost corresponds to a past implementation
// of StaticGraph<> @CL 116144340.
template <typename NodeIndexType = int32_t, typename ArcIndexType = int32_t>
class StaticGraph : public BaseGraph<NodeIndexType, ArcIndexType, false> {
typedef BaseGraph<NodeIndexType, ArcIndexType, false> Base;
using Base::arc_capacity_;
using Base::const_capacities_;
using Base::node_capacity_;
using Base::num_arcs_;
using Base::num_nodes_;
public:
using Base::IsArcValid;
StaticGraph() : is_built_(false), arc_in_order_(true), last_tail_seen_(0) {}
StaticGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity)
: is_built_(false), arc_in_order_(true), last_tail_seen_(0) {
this->Reserve(num_nodes, arc_capacity);
this->FreezeCapacities();
this->AddNode(num_nodes - 1);
}
// Shortcut to directly create a finalized graph, i.e. Build() is called.
template <class ArcContainer> // e.g. vector<pair<int, int>>.
static StaticGraph FromArcs(NodeIndexType num_nodes,
const ArcContainer& arcs);
// Do not use directly. See instead the arc iteration functions below.
class OutgoingArcIterator;
NodeIndexType Head(ArcIndexType arc) const;
NodeIndexType Tail(ArcIndexType arc) const;
ArcIndexType OutDegree(NodeIndexType node) const; // Work in O(1).
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
// This loops over the heads of the OutgoingArcs(node). It is just a more
// convenient way to achieve this. Moreover this interface is used by some
// graph algorithms.
absl::Span<const NodeIndexType> operator[](NodeIndexType node) const;
void ReserveNodes(NodeIndexType bound) override;
void ReserveArcs(ArcIndexType bound) override;
void AddNode(NodeIndexType node);
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head);
void Build() { Build(nullptr); }
void Build(std::vector<ArcIndexType>* permutation);
private:
ArcIndexType DirectArcLimit(NodeIndexType node) const {
DCHECK(is_built_);
DCHECK(Base::IsNodeValid(node));
return node + 1 < num_nodes_ ? start_[node + 1] : num_arcs_;
}
bool is_built_;
bool arc_in_order_;
NodeIndexType last_tail_seen_;
std::vector<ArcIndexType> start_;
std::vector<NodeIndexType> head_;
std::vector<NodeIndexType> tail_;
};
// Extends the ListGraph by also storing the reverse arcs.
// This class also documents the Graph interface related to reverse arc.
// - NodeIndexType can be unsigned, but ArcIndexType must be signed.
// - It has most of the same advantanges and disadvantages as ListGraph.
// - It takes 2 * ArcIndexType * node_capacity()
// + 2 * (ArcIndexType + NodeIndexType) * arc_capacity() memory.
template <typename NodeIndexType = int32_t, typename ArcIndexType = int32_t>
class ReverseArcListGraph
: public BaseGraph<NodeIndexType, ArcIndexType, true> {
static_assert(std::is_signed_v<ArcIndexType>, "ArcIndexType must be signed");
typedef BaseGraph<NodeIndexType, ArcIndexType, true> Base;
using Base::arc_capacity_;
using Base::const_capacities_;
using Base::node_capacity_;
using Base::num_arcs_;
using Base::num_nodes_;
public:
using Base::IsArcValid;
ReverseArcListGraph() {}
ReverseArcListGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity) {
this->Reserve(num_nodes, arc_capacity);
this->FreezeCapacities();
this->AddNode(num_nodes - 1);
}
// Returns the opposite arc of a given arc. That is the reverse arc of the
// given forward arc or the forward arc of a given reverse arc.
ArcIndexType OppositeArc(ArcIndexType arc) const;
// Do not use directly. See instead the arc iteration functions below.
class OutgoingOrOppositeIncomingArcIterator;
class OppositeIncomingArcIterator;
class IncomingArcIterator;
class OutgoingArcIterator;
class OutgoingHeadIterator;
// ReverseArcListGraph<>::OutDegree() and ::InDegree() work in O(degree).
ArcIndexType OutDegree(NodeIndexType node) const;
ArcIndexType InDegree(NodeIndexType node) const;
// Arc iterations functions over the arcs touching a node (see the top-level
// comment for the different types). To be used as follows:
// for (const Graph::ArcIndex arc : IterationFunction(node)) { ... }
//
// The StartingFrom() version are similar, but restart the iteration from a
// given arc position (which must be valid in the iteration context).
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcs(
NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node,
ArcIndexType from) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
// This loops over the heads of the OutgoingArcs(node). It is just a more
// convenient way to achieve this. Moreover this interface is used by some
// graph algorithms.
BeginEndWrapper<OutgoingHeadIterator> operator[](NodeIndexType node) const;
NodeIndexType Head(ArcIndexType arc) const;
NodeIndexType Tail(ArcIndexType arc) const;
void ReserveNodes(NodeIndexType bound) override;
void ReserveArcs(ArcIndexType bound) override;
void AddNode(NodeIndexType node);
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head);
void Build() { Build(nullptr); }
void Build(std::vector<ArcIndexType>* permutation);
private:
std::vector<ArcIndexType> start_;
std::vector<ArcIndexType> reverse_start_;
SVector<ArcIndexType> next_;
SVector<NodeIndexType> head_;
};
// StaticGraph with reverse arc.
// - NodeIndexType can be unsigned, but ArcIndexType must be signed.
// - It has most of the same advantanges and disadvantages as StaticGraph.
// - It takes 2 * ArcIndexType * node_capacity()
// + 2 * (ArcIndexType + NodeIndexType) * arc_capacity() memory.
// - If the ArcIndexPermutation is needed, then an extra ArcIndexType *
// arc_capacity() is needed for it.
// - The reverse arcs from a node are sorted by head (so we could add a log()
// time lookup function).
template <typename NodeIndexType = int32_t, typename ArcIndexType = int32_t>
class ReverseArcStaticGraph
: public BaseGraph<NodeIndexType, ArcIndexType, true> {
static_assert(std::is_signed_v<ArcIndexType>, "ArcIndexType must be signed");
typedef BaseGraph<NodeIndexType, ArcIndexType, true> Base;
using Base::arc_capacity_;
using Base::const_capacities_;
using Base::node_capacity_;
using Base::num_arcs_;
using Base::num_nodes_;
public:
using Base::IsArcValid;
ReverseArcStaticGraph() : is_built_(false) {}
ReverseArcStaticGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity)
: is_built_(false) {
this->Reserve(num_nodes, arc_capacity);
this->FreezeCapacities();
this->AddNode(num_nodes - 1);
}
// Deprecated.
class OutgoingOrOppositeIncomingArcIterator;
class OppositeIncomingArcIterator;
class IncomingArcIterator;
class OutgoingArcIterator;
// ReverseArcStaticGraph<>::OutDegree() and ::InDegree() work in O(1).
ArcIndexType OutDegree(NodeIndexType node) const;
ArcIndexType InDegree(NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcs(
NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node,
ArcIndexType from) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
// This loops over the heads of the OutgoingArcs(node). It is just a more
// convenient way to achieve this. Moreover this interface is used by some
// graph algorithms.
absl::Span<const NodeIndexType> operator[](NodeIndexType node) const;
ArcIndexType OppositeArc(ArcIndexType arc) const;
// TODO(user): support Head() and Tail() before Build(), like StaticGraph<>.
NodeIndexType Head(ArcIndexType arc) const;
NodeIndexType Tail(ArcIndexType arc) const;
void ReserveArcs(ArcIndexType bound) override;
void AddNode(NodeIndexType node);
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head);
void Build() { Build(nullptr); }
void Build(std::vector<ArcIndexType>* permutation);
private:
ArcIndexType DirectArcLimit(NodeIndexType node) const {
DCHECK(is_built_);
DCHECK(Base::IsNodeValid(node));
return node + 1 < num_nodes_ ? start_[node + 1] : num_arcs_;
}
ArcIndexType ReverseArcLimit(NodeIndexType node) const {
DCHECK(is_built_);
DCHECK(Base::IsNodeValid(node));
return node + 1 < num_nodes_ ? reverse_start_[node + 1] : 0;
}
bool is_built_;
std::vector<ArcIndexType> start_;
std::vector<ArcIndexType> reverse_start_;
SVector<NodeIndexType> head_;
SVector<ArcIndexType> opposite_;
};
// This graph is a mix between the ReverseArcListGraph and the
// ReverseArcStaticGraph. It uses less memory:
// - It takes 2 * ArcIndexType * node_capacity()
// + (2 * NodeIndexType + ArcIndexType) * arc_capacity() memory.
// - If the ArcIndexPermutation is needed, then an extra ArcIndexType *
// arc_capacity() is needed for it.
template <typename NodeIndexType = int32_t, typename ArcIndexType = int32_t>
class ReverseArcMixedGraph
: public BaseGraph<NodeIndexType, ArcIndexType, true> {
typedef BaseGraph<NodeIndexType, ArcIndexType, true> Base;
using Base::arc_capacity_;
using Base::const_capacities_;
using Base::node_capacity_;
using Base::num_arcs_;
using Base::num_nodes_;
public:
using Base::IsArcValid;
ReverseArcMixedGraph() : is_built_(false) {}
ReverseArcMixedGraph(NodeIndexType num_nodes, ArcIndexType arc_capacity)
: is_built_(false) {
this->Reserve(num_nodes, arc_capacity);
this->FreezeCapacities();
this->AddNode(num_nodes - 1);
}
// Deprecated.
class OutgoingOrOppositeIncomingArcIterator;
class OppositeIncomingArcIterator;
class IncomingArcIterator;
class OutgoingArcIterator;
ArcIndexType OutDegree(NodeIndexType node) const; // O(1)
ArcIndexType InDegree(NodeIndexType node) const; // O(in-degree)
BeginEndWrapper<OutgoingArcIterator> OutgoingArcs(NodeIndexType node) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcs(NodeIndexType node) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcs(
NodeIndexType node) const;
BeginEndWrapper<OutgoingArcIterator> OutgoingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
BeginEndWrapper<IncomingArcIterator> IncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
BeginEndWrapper<OutgoingOrOppositeIncomingArcIterator>
OutgoingOrOppositeIncomingArcsStartingFrom(NodeIndexType node,
ArcIndexType from) const;
BeginEndWrapper<OppositeIncomingArcIterator> OppositeIncomingArcsStartingFrom(
NodeIndexType node, ArcIndexType from) const;
// This loops over the heads of the OutgoingArcs(node). It is just a more
// convenient way to achieve this. Moreover this interface is used by some
// graph algorithms.
absl::Span<const NodeIndexType> operator[](NodeIndexType node) const;
ArcIndexType OppositeArc(ArcIndexType arc) const;
// TODO(user): support Head() and Tail() before Build(), like StaticGraph<>.
NodeIndexType Head(ArcIndexType arc) const;
NodeIndexType Tail(ArcIndexType arc) const;
void ReserveArcs(ArcIndexType bound) override;
void AddNode(NodeIndexType node);
ArcIndexType AddArc(NodeIndexType tail, NodeIndexType head);
void Build() { Build(nullptr); }
void Build(std::vector<ArcIndexType>* permutation);
private:
ArcIndexType DirectArcLimit(NodeIndexType node) const {
DCHECK(is_built_);
DCHECK(Base::IsNodeValid(node));
return node + 1 < num_nodes_ ? start_[node + 1] : num_arcs_;
}
bool is_built_;
std::vector<ArcIndexType> start_;
std::vector<ArcIndexType> reverse_start_;
std::vector<ArcIndexType> next_;
SVector<NodeIndexType> head_;
};
// Permutes the elements of array_to_permute: element #i will be moved to
// position permutation[i]. permutation must be either empty (in which case
// nothing happens), or a permutation of [0, permutation.size()).
//
// The algorithm is fast but need extra memory for a copy of the permuted part
// of array_to_permute.
//
// TODO(user): consider slower but more memory efficient implementations that
// follow the cycles of the permutation and use a bitmap to indicate what has
// been permuted or to mark the beginning of each cycle.
// Some compiler do not know typeof(), so we have to use this extra function
// internally.
template <class IntVector, class Array, class ElementType>
void PermuteWithExplicitElementType(const IntVector& permutation,
Array* array_to_permute,
ElementType unused) {
std::vector<ElementType> temp(permutation.size());
for (size_t i = 0; i < permutation.size(); ++i) {
temp[i] = (*array_to_permute)[i];
}
for (size_t i = 0; i < permutation.size(); ++i) {
(*array_to_permute)[permutation[i]] = temp[i];
}
}
template <class IntVector, class Array>
void Permute(const IntVector& permutation, Array* array_to_permute) {
if (permutation.empty()) {
return;
}
PermuteWithExplicitElementType(permutation, array_to_permute,
(*array_to_permute)[0]);
}
// We need a specialization for vector<bool>, because the default code uses
// (*array_to_permute)[0] as ElementType, which isn't 'bool' in that case.
template <class IntVector>
void Permute(const IntVector& permutation,
std::vector<bool>* array_to_permute) {
if (permutation.empty()) {
return;
}
bool unused = false;
PermuteWithExplicitElementType(permutation, array_to_permute, unused);
}
// A vector-like class where valid indices are in [- size_, size_) and reserved
// indices for future growth are in [- capacity_, capacity_). It is used to hold
// arc related information for graphs with reverse arcs.
// It supports only up to 2^31-1 elements, for compactness. If you ever need
// more, consider using templates for the size/capacity integer types.
//
// Sample usage:
//
// SVector<int> v;
// v.grow(left_value, right_value);
// v.resize(10);
// v.clear();
// v.swap(new_v);
// std:swap(v[i], v[~i]);
template <typename T>
class SVector {
public:
SVector() : base_(nullptr), size_(0), capacity_(0) {}
~SVector() { clear_and_dealloc(); }
// Copy constructor and assignment operator.
SVector(const SVector& other) : SVector() { *this = other; }
SVector& operator=(const SVector& other) {
if (capacity_ < other.size_) {
clear_and_dealloc();
// NOTE(user): Alternatively, our capacity could inherit from the other
// vector's capacity, which can be (much) greater than its size.
capacity_ = other.size_;
base_ = Allocate(capacity_);
CHECK(base_ != nullptr);
base_ += capacity_;
} else { // capacity_ >= other.size
clear();
}
// Perform the actual copy of the payload.
size_ = other.size_;
CopyInternal(other, std::is_integral<T>());
return *this;
}
// Move constructor and move assignment operator.
SVector(SVector&& other) noexcept : SVector() { swap(other); }
SVector& operator=(SVector&& other) noexcept {
// NOTE(user): We could just swap() and let the other's destruction take
// care of the clean-up, but it is probably less bug-prone to perform the
// destruction immediately.
clear_and_dealloc();
swap(other);
return *this;
}
T& operator[](int n) {
DCHECK_LT(n, size_);
DCHECK_GE(n, -size_);
return base_[n];
}
const T& operator[](int n) const {
DCHECK_LT(n, size_);
DCHECK_GE(n, -size_);
return base_[n];
}
void resize(int n) {
reserve(n);
for (int i = -n; i < -size_; ++i) {
new (base_ + i) T();
}
for (int i = size_; i < n; ++i) {
new (base_ + i) T();
}
for (int i = -size_; i < -n; ++i) {
base_[i].~T();
}
for (int i = n; i < size_; ++i) {
base_[i].~T();
}
size_ = n;
}
void clear() { resize(0); }
T* data() const { return base_; }
void swap(SVector<T>& x) noexcept {
std::swap(base_, x.base_);
std::swap(size_, x.size_);
std::swap(capacity_, x.capacity_);
}
void reserve(int n) {
DCHECK_GE(n, 0);
DCHECK_LE(n, max_size());
if (n > capacity_) {
const int new_capacity = std::min(n, max_size());
T* new_storage = Allocate(new_capacity);
CHECK(new_storage != nullptr);
T* new_base = new_storage + new_capacity;
// TODO(user): in C++17 we could use std::uninitialized_move instead
// of this loop.
for (int i = -size_; i < size_; ++i) {
new (new_base + i) T(std::move(base_[i]));
}
int saved_size = size_;
clear_and_dealloc();
size_ = saved_size;
base_ = new_base;
capacity_ = new_capacity;
}
}
// NOTE(user): This doesn't currently support movable-only objects, but we
// could fix that.
void grow(const T& left = T(), const T& right = T()) {
if (size_ == capacity_) {
// We have to copy the elements because they are allowed to be element of
// *this.
T left_copy(left); // NOLINT
T right_copy(right); // NOLINT
reserve(NewCapacity(1));
new (base_ + size_) T(right_copy);
new (base_ - size_ - 1) T(left_copy);
++size_;
} else {
new (base_ + size_) T(right);
new (base_ - size_ - 1) T(left);
++size_;
}
}
int size() const { return size_; }
int capacity() const { return capacity_; }
int max_size() const { return std::numeric_limits<int>::max(); }
void clear_and_dealloc() {
if (base_ == nullptr) return;
clear();
if (capacity_ > 0) {
free(base_ - capacity_);
}
capacity_ = 0;
base_ = nullptr;
}
private:
// Copies other.base_ to base_ in this SVector. Avoids iteration by copying
// entire memory range in a single shot for the most commonly used integral
// types which should be safe to copy in this way.
void CopyInternal(const SVector& other, std::true_type) {
std::memcpy(base_ - other.size_, other.base_ - other.size_,
2LL * other.size_ * sizeof(T));
}
// Copies other.base_ to base_ in this SVector. Safe for all types as it uses
// constructor for each entry.
void CopyInternal(const SVector& other, std::false_type) {
for (int i = -size_; i < size_; ++i) {
new (base_ + i) T(other.base_[i]);
}
}
T* Allocate(int capacity) const {
return absl::IgnoreLeak(
static_cast<T*>(malloc(2LL * capacity * sizeof(T))));
}
int NewCapacity(int delta) {
// TODO(user): check validity.
double candidate = 1.3 * static_cast<double>(capacity_);
if (candidate > static_cast<double>(max_size())) {
candidate = static_cast<double>(max_size());
}
int new_capacity = static_cast<int>(candidate);
if (new_capacity > capacity_ + delta) {
return new_capacity;
}
return capacity_ + delta;
}
T* base_; // Pointer to the element of index 0.
int size_; // Valid index are [- size_, size_).
int capacity_; // Reserved index are [- capacity_, capacity_).
};
// BaseGraph implementation ----------------------------------------------------
template <typename NodeIndexType, typename ArcIndexType, bool HasReverseArcs>
IntegerRange<NodeIndexType>
BaseGraph<NodeIndexType, ArcIndexType, HasReverseArcs>::AllNodes() const {
return IntegerRange<NodeIndexType>(0, num_nodes_);
}
template <typename NodeIndexType, typename ArcIndexType, bool HasReverseArcs>
IntegerRange<ArcIndexType>
BaseGraph<NodeIndexType, ArcIndexType, HasReverseArcs>::AllForwardArcs() const {
return IntegerRange<ArcIndexType>(0, num_arcs_);
}
template <typename NodeIndexType, typename ArcIndexType, bool HasReverseArcs>
const NodeIndexType
BaseGraph<NodeIndexType, ArcIndexType, HasReverseArcs>::kNilNode =
std::numeric_limits<NodeIndexType>::max();
template <typename NodeIndexType, typename ArcIndexType, bool HasReverseArcs>
const ArcIndexType
BaseGraph<NodeIndexType, ArcIndexType, HasReverseArcs>::kNilArc =
std::numeric_limits<ArcIndexType>::max();
template <typename NodeIndexType, typename ArcIndexType, bool HasReverseArcs>
NodeIndexType
BaseGraph<NodeIndexType, ArcIndexType, HasReverseArcs>::node_capacity() const {
// TODO(user): Is it needed? remove completely? return the real capacities
// at the cost of having a different implementation for each graphs?
return node_capacity_ > num_nodes_ ? node_capacity_ : num_nodes_;
}
template <typename NodeIndexType, typename ArcIndexType, bool HasReverseArcs>
ArcIndexType
BaseGraph<NodeIndexType, ArcIndexType, HasReverseArcs>::arc_capacity() const {
// TODO(user): Same questions as the ones in node_capacity().