forked from google/or-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ebert_graph.h
2124 lines (1875 loc) · 79.9 KB
/
ebert_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-2018 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.
#ifndef OR_TOOLS_GRAPH_EBERT_GRAPH_H_
#define OR_TOOLS_GRAPH_EBERT_GRAPH_H_
// A few variations on a theme of the "star" graph representation by
// Ebert, as described in J. Ebert, "A versatile data structure for
// edge-oriented graph algorithms." Communications of the ACM
// 30(6):513-519 (June 1987).
// http://portal.acm.org/citation.cfm?id=214769
//
// In this file there are three representations that have much in
// common. The general one, called simply EbertGraph, contains both
// forward- and backward-star representations. The other, called
// ForwardEbertGraph, contains only the forward-star representation of
// the graph, and is appropriate for applications where the reverse
// arcs are not needed.
//
// The point of including all the representations in this one file is
// to capitalize, where possible, on the commonalities among them, and
// those commonalities are mostly factored out into base classes as
// described below. Despite the commonalities, however, each of the
// three representations presents a somewhat different interface
// because of their different underlying semantics. A quintessential
// example is that the AddArc() method, very natural for the
// EbertGraph representation, cannot exist for an inherently static
// representation like ForwardStaticGraph.
//
// Many clients are expected to use the interfaces to the graph
// objects directly, but some clients are parameterized by graph type
// and need a consistent interface for their underlying graph
// objects. For such clients, a small library of class templates is
// provided to give a consistent interface to clients where the
// underlying graph interfaces differ. Examples are the
// AnnotatedGraphBuildManager<> template, which provides a uniform
// interface for building the various types of graphs; and the
// TailArrayManager<> template, which provides a uniform interface for
// applications that need to map from arc indices to arc tail nodes,
// accounting for the fact that such a mapping has to be requested
// explicitly from the ForwardStaticGraph and ForwardStarGraph
// representations.
//
// There are two base class templates, StarGraphBase, and
// EbertGraphBase; their purpose is to hold methods and data
// structures that are in common among their descendants. Only classes
// that are leaves in the following hierarchy tree are eligible for
// free-standing instantiation and use by clients. The parentheses
// around StarGraphBase and EbertGraphBase indicate that they should
// not normally be instantiated by clients:
//
// (StarGraphBase) |
// / \ |
// / \ |
// / \ |
// / \ |
// (EbertGraphBase) ForwardStaticGraph |
// / \ |
// / \ |
// EbertGraph ForwardEbertGraph |
//
// In the general EbertGraph case, the graph is represented with three
// arrays.
// Let n be the number of nodes and m be the number of arcs.
// Let i be an integer in [0..m-1], denoting the index of an arc.
// * head_[i] contains the end-node of arc i,
// * head_[-i-1] contains the start-node of arc i.
// Note that in two's-complement arithmetic, -i-1 = ~i.
// Consequently:
// * head_[~i] contains the end-node of the arc reverse to arc i,
// * head_[i] contains the start-node of the arc reverse to arc i.
// Note that if arc (u, v) is defined, then the data structure also stores
// (v, u).
// Arc ~i thus denotes the arc reverse to arc i.
// This is what makes this representation useful for undirected graphs and for
// implementing algorithms like bidirectional shortest paths.
// Also note that the representation handles multi-graphs. If several arcs
// going from node u to node v are added to the graph, they will be handled as
// separate arcs.
//
// Now, for an integer u in [0..n-1] denoting the index of a node:
// * first_incident_arc_[u] denotes the first arc in the adjacency list of u.
// * going from an arc i, the adjacency list can be traversed using
// j = next_adjacent_arc_[i].
//
// The EbertGraph implementation has the following benefits:
// * It is able to handle both directed or undirected graphs.
// * Being based on indices, it is easily serializable. Only the contents
// of the head_ array need to be stored. Even so, serialization is
// currently not implemented.
// * The node indices and arc indices can be stored in 32 bits, while
// still allowing to go a bit further than the 4-gigabyte
// limitation (48 gigabytes for a pure graph, without capacities or
// costs.)
// * The representation can be recomputed if edges have been loaded from
// * The representation can be recomputed if edges have been loaded from
// external memory or if edges have been re-ordered.
// * The memory consumption is: 2 * m * sizeof(NodeIndexType)
// + 2 * m * sizeof(ArcIndexType)
// + n * sizeof(ArcIndexType)
// plus a small constant.
//
// The EbertGraph implementation differs from the implementation described in
// [Ebert 1987] in the following respects:
// * arcs are represented using an (i, ~i) approach, whereas Ebert used
// (i, -i). Indices for direct arcs thus start at 0, in a fashion that is
// compatible with the index numbering in C and C++. Note that we also tested
// a (2*i, 2*i+1) storage pattern, which did not show any speed benefit, and
// made the use of the API much more difficult.
// * because of this, the 'nil' values for nodes and arcs are not 0, as Ebert
// first described. The value for the 'nil' node is set to -1, while the
// value for the 'nil' arc is set to the smallest integer representable with
// ArcIndexSize bytes.
// * it is possible to add arcs to the graph, with AddArc, in a much simpler
// way than described by Ebert.
// * TODO(user) although it is already possible, using the
// GroupForwardArcsByFunctor method, to group all the outgoing (resp.
// incoming) arcs of a node, the iterator logic could still be improved to
// allow traversing the outgoing (resp. incoming) arcs in O(out_degree(node))
// (resp. O(in_degree(node))) instead of O(degree(node)).
// * TODO(user) it is possible to implement arc deletion and garbage collection
// in an efficient (relatively) manner. For the time being we haven't seen an
// application for this.
//
// The ForwardEbertGraph representation is like the EbertGraph case described
// above, with the following modifications:
// * The part of the head_[] array with negative indices is absent. In its
// place is a pointer tail_ which, if assigned, points to an array of tail
// nodes indexed by (nonnegative) arc index. In typical usage tail_ is NULL
// and the memory for the tail nodes need not be allocated.
// * The array of arc tails can be allocated as needed and populated from the
// adjacency lists of the graph.
// * Representing only the forward star of each node implies that the graph
// cannot be serialized directly nor rebuilt from scratch from just the head_
// array. Rebuilding from scratch requires constructing the array of arc
// tails from the adjacency lists first, and serialization can be done either
// by first constructing the array of arc tails from the adjacency lists, or
// by serializing directly from the adjacency lists.
// * The memory consumption is: m * sizeof(NodeIndexType)
// + m * sizeof(ArcIndexType)
// + n * sizeof(ArcIndexType)
// plus a small constant when the array of arc tails is absent. Allocating
// the arc tail array adds another m * sizeof(NodeIndexType).
//
// The ForwardStaticGraph representation is restricted yet farther
// than ForwardEbertGraph, with the benefit that it provides higher
// performance to those applications that can use it.
// * As with ForwardEbertGraph, the presence of the array of arc
// tails is optional.
// * The outgoing adjacency list for each node is stored in a
// contiguous segment of the head_[] array, obviating the
// next_adjacent_arc_ structure entirely and ensuring good locality
// of reference for applications that iterate over outgoing
// adjacency lists.
// * The memory consumption is: m * sizeof(NodeIndexType)
// + n * sizeof(ArcIndexType)
// plus a small constant when the array of arc tails is absent. Allocating
// the arc tail array adds another m * sizeof(NodeIndexType).
#include <algorithm>
#include <limits>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "absl/strings/str_cat.h"
#include "ortools/base/integral_types.h"
#include "ortools/base/logging.h"
#include "ortools/base/macros.h"
#include "ortools/util/permutation.h"
#include "ortools/util/zvector.h"
namespace operations_research {
// Forward declarations.
template <typename NodeIndexType, typename ArcIndexType>
class EbertGraph;
template <typename NodeIndexType, typename ArcIndexType>
class ForwardEbertGraph;
template <typename NodeIndexType, typename ArcIndexType>
class ForwardStaticGraph;
// Standard instantiation of ForwardEbertGraph (named 'ForwardStarGraph') of
// EbertGraph (named 'StarGraph'); and relevant type shortcuts. Unless their use
// cases prevent them from doing so, users are encouraged to use StarGraph or
// ForwardStarGraph according to whether or not they require reverse arcs to be
// represented explicitly. Along with either graph representation, the other
// type shortcuts here will often come in handy.
typedef int32 NodeIndex;
typedef int32 ArcIndex;
typedef int64 FlowQuantity;
typedef int64 CostValue;
typedef EbertGraph<NodeIndex, ArcIndex> StarGraph;
typedef ForwardEbertGraph<NodeIndex, ArcIndex> ForwardStarGraph;
typedef ForwardStaticGraph<NodeIndex, ArcIndex> ForwardStarStaticGraph;
typedef ZVector<NodeIndex> NodeIndexArray;
typedef ZVector<ArcIndex> ArcIndexArray;
typedef ZVector<FlowQuantity> QuantityArray;
typedef ZVector<CostValue> CostArray;
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
class StarGraphBase {
public:
// The index of the 'nil' node in the graph.
static const NodeIndexType kNilNode;
// The index of the 'nil' arc in the graph.
static const ArcIndexType kNilArc;
// The index of the first node in the graph.
static const NodeIndexType kFirstNode;
// The index of the first arc in the graph.
static const ArcIndexType kFirstArc;
// The maximum possible number of nodes in the graph. (The maximum
// index is kMaxNumNodes-1, since indices start at 0. Unfortunately
// we waste a value representing this and the max_num_nodes_ member.)
static const NodeIndexType kMaxNumNodes;
// The maximum possible number of arcs in the graph. (The maximum
// index is kMaxNumArcs-1, since indices start at 0. Unfortunately
// we waste a value representing this and the max_num_arcs_ member.)
static const ArcIndexType kMaxNumArcs;
// Returns the number of nodes in the graph.
NodeIndexType num_nodes() const { return num_nodes_; }
// Returns the number of original arcs in the graph
// (The ones with positive indices.)
ArcIndexType num_arcs() const { return num_arcs_; }
// Returns one more than the largest index of an extant node,
// meaning a node that is mentioned as the head or tail of some arc
// in the graph. To be used as a helper when clients need to
// dimension or iterate over arrays of node annotation information.
NodeIndexType end_node_index() const { return kFirstNode + num_nodes_; }
// Returns one more than the largest index of an extant direct
// arc. To be used as a helper when clients need to dimension or
// iterate over arrays of arc annotation information.
ArcIndexType end_arc_index() const { return kFirstArc + num_arcs_; }
// Returns the maximum possible number of nodes in the graph.
NodeIndexType max_num_nodes() const { return max_num_nodes_; }
// Returns the maximum possible number of original arcs in the graph.
// (The ones with positive indices.)
ArcIndexType max_num_arcs() const { return max_num_arcs_; }
// Returns one more than the largest valid index of a node. To be
// used as a helper when clients need to dimension or iterate over
// arrays of node annotation information.
NodeIndexType max_end_node_index() const {
return kFirstNode + max_num_nodes_;
}
// Returns one more than the largest valid index of a direct arc. To
// be used as a helper when clients need to dimension or iterate
// over arrays of arc annotation information.
ArcIndexType max_end_arc_index() const { return kFirstArc + max_num_arcs_; }
// Utility function to check that a node index is within the bounds AND
// different from kNilNode.
// Returns true if node is in the range [kFirstNode .. max_num_nodes_).
// It is exported so that users of the DerivedGraph class can use it.
// To be used in a DCHECK; also used internally to validate
// arguments passed to our methods from clients (e.g., AddArc()).
bool IsNodeValid(NodeIndexType node) const {
return node >= kFirstNode && node < max_num_nodes_;
}
// Returns the first arc going from tail to head, if it exists, or kNilArc
// if such an arc does not exist.
ArcIndexType LookUpArc(const NodeIndexType tail,
const NodeIndexType head) const {
for (ArcIndexType arc = FirstOutgoingArc(tail); arc != kNilArc;
arc = ThisAsDerived()->NextOutgoingArc(tail, arc)) {
if (Head(arc) == head) {
return arc;
}
}
return kNilArc;
}
// Returns the head or end-node of arc.
NodeIndexType Head(const ArcIndexType arc) const {
DCHECK(ThisAsDerived()->CheckArcValidity(arc));
return head_[arc];
}
std::string NodeDebugString(const NodeIndexType node) const {
if (node == kNilNode) {
return "NilNode";
} else {
return absl::StrCat(static_cast<int64>(node));
}
}
std::string ArcDebugString(const ArcIndexType arc) const {
if (arc == kNilArc) {
return "NilArc";
} else {
return absl::StrCat(static_cast<int64>(arc));
}
}
#if !defined(SWIG)
// Iterator class for traversing all the nodes in the graph.
class NodeIterator {
public:
explicit NodeIterator(const DerivedGraph& graph)
: graph_(graph), head_(graph_.StartNode(kFirstNode)) {}
// Returns true unless all the nodes have been traversed.
bool Ok() const { return head_ != kNilNode; }
// Advances the current node index.
void Next() { head_ = graph_.NextNode(head_); }
// Returns the index of the node currently pointed to by the iterator.
NodeIndexType Index() const { return head_; }
private:
// A reference to the current DerivedGraph considered.
const DerivedGraph& graph_;
// The index of the current node considered.
NodeIndexType head_;
};
// Iterator class for traversing the arcs in the graph.
class ArcIterator {
public:
explicit ArcIterator(const DerivedGraph& graph)
: graph_(graph), arc_(graph_.StartArc(kFirstArc)) {}
// Returns true unless all the arcs have been traversed.
bool Ok() const { return arc_ != kNilArc; }
// Advances the current arc index.
void Next() { arc_ = graph_.NextArc(arc_); }
// Returns the index of the arc currently pointed to by the iterator.
ArcIndexType Index() const { return arc_; }
private:
// A reference to the current DerivedGraph considered.
const DerivedGraph& graph_;
// The index of the current arc considered.
ArcIndexType arc_;
};
// Iterator class for traversing the outgoing arcs associated to a given node.
class OutgoingArcIterator {
public:
OutgoingArcIterator(const DerivedGraph& graph, NodeIndexType node)
: graph_(graph),
node_(graph_.StartNode(node)),
arc_(graph_.StartArc(graph_.FirstOutgoingArc(node))) {
DCHECK(CheckInvariant());
}
// This constructor takes an arc as extra argument and makes the iterator
// start at arc.
OutgoingArcIterator(const DerivedGraph& graph, NodeIndexType node,
ArcIndexType arc)
: graph_(graph),
node_(graph_.StartNode(node)),
arc_(graph_.StartArc(arc)) {
DCHECK(CheckInvariant());
}
// Can only assign from an iterator on the same graph.
void operator=(const OutgoingArcIterator& iterator) {
DCHECK(&iterator.graph_ == &graph_);
node_ = iterator.node_;
arc_ = iterator.arc_;
}
// Returns true unless all the outgoing arcs have been traversed.
bool Ok() const { return arc_ != kNilArc; }
// Advances the current outgoing arc index.
void Next() {
arc_ = graph_.NextOutgoingArc(node_, arc_);
DCHECK(CheckInvariant());
}
// Returns the index of the arc currently pointed to by the iterator.
ArcIndexType Index() const { return arc_; }
private:
// Returns true if the invariant for the iterator is verified.
// To be used in a DCHECK.
bool CheckInvariant() const {
if (arc_ == kNilArc) {
return true; // This occurs when the iterator has reached the end.
}
DCHECK(graph_.IsOutgoing(arc_, node_));
return true;
}
// A reference to the current DerivedGraph considered.
const DerivedGraph& graph_;
// The index of the node on which arcs are iterated.
NodeIndexType node_;
// The index of the current arc considered.
ArcIndexType arc_;
};
#endif // SWIG
protected:
StarGraphBase()
: max_num_nodes_(0),
max_num_arcs_(0),
num_nodes_(0),
num_arcs_(0),
first_incident_arc_() {}
~StarGraphBase() {}
// Returns kNilNode if the graph has no nodes or node if it has at least one
// node. Useful for initializing iterators correctly in the case of empty
// graphs.
NodeIndexType StartNode(NodeIndexType node) const {
return num_nodes_ == 0 ? kNilNode : node;
}
// Returns kNilArc if the graph has no arcs arc if it has at least one arc.
// Useful for initializing iterators correctly in the case of empty graphs.
ArcIndexType StartArc(ArcIndexType arc) const {
return num_arcs_ == 0 ? kNilArc : arc;
}
// Returns the node following the argument in the graph.
// Returns kNilNode (= end) if the range of nodes has been exhausted.
// It is called by NodeIterator::Next() and as such does not expect to be
// passed an argument equal to kNilNode.
// This is why the return line is simplified from
// return (node == kNilNode || next_node >= num_nodes_)
// ? kNilNode : next_node;
// to
// return next_node < num_nodes_ ? next_node : kNilNode;
NodeIndexType NextNode(const NodeIndexType node) const {
DCHECK(IsNodeValid(node));
const NodeIndexType next_node = node + 1;
return next_node < num_nodes_ ? next_node : kNilNode;
}
// Returns the arc following the argument in the graph.
// Returns kNilArc (= end) if the range of arcs has been exhausted.
// It is called by ArcIterator::Next() and as such does not expect to be
// passed an argument equal to kNilArc.
// This is why the return line is simplified from
// return ( arc == kNilArc || next_arc >= num_arcs_) ? kNilArc : next_arc;
// to
// return next_arc < num_arcs_ ? next_arc : kNilArc;
ArcIndexType NextArc(const ArcIndexType arc) const {
DCHECK(ThisAsDerived()->CheckArcValidity(arc));
const ArcIndexType next_arc = arc + 1;
return next_arc < num_arcs_ ? next_arc : kNilArc;
}
// Returns the first outgoing arc for node.
ArcIndexType FirstOutgoingArc(const NodeIndexType node) const {
DCHECK(IsNodeValid(node));
return ThisAsDerived()->FindNextOutgoingArc(
ThisAsDerived()->FirstOutgoingOrOppositeIncomingArc(node));
}
// The maximum number of nodes that the graph can hold.
NodeIndexType max_num_nodes_;
// The maximum number of arcs that the graph can hold.
ArcIndexType max_num_arcs_;
// The maximum index of the node currently held by the graph.
NodeIndexType num_nodes_;
// The current number of arcs held by the graph.
ArcIndexType num_arcs_;
// Array of node indices. head_[i] contains the head node of arc i.
ZVector<NodeIndexType> head_;
// Array of arc indices. first_incident_arc_[i] contains the first arc
// incident to node i.
ZVector<ArcIndexType> first_incident_arc_;
private:
// Shorthand: returns a const DerivedGraph*-typed version of our
// "this" pointer.
inline const DerivedGraph* ThisAsDerived() const {
return static_cast<const DerivedGraph*>(this);
}
// Shorthand: returns a DerivedGraph*-typed version of our "this"
// pointer.
inline DerivedGraph* ThisAsDerived() {
return static_cast<DerivedGraph*>(this);
}
};
template <typename NodeIndexType, typename ArcIndexType>
class PermutationIndexComparisonByArcHead {
public:
explicit PermutationIndexComparisonByArcHead(
const ZVector<NodeIndexType>& head)
: head_(head) {}
bool operator()(ArcIndexType a, ArcIndexType b) const {
return head_[a] < head_[b];
}
private:
const ZVector<NodeIndexType>& head_;
};
template <typename NodeIndexType, typename ArcIndexType>
class ForwardStaticGraph
: public StarGraphBase<NodeIndexType, ArcIndexType,
ForwardStaticGraph<NodeIndexType, ArcIndexType> > {
typedef StarGraphBase<NodeIndexType, ArcIndexType,
ForwardStaticGraph<NodeIndexType, ArcIndexType> >
Base;
friend class StarGraphBase<NodeIndexType, ArcIndexType,
ForwardStaticGraph<NodeIndexType, ArcIndexType> >;
using Base::ArcDebugString;
using Base::NodeDebugString;
using Base::first_incident_arc_;
using Base::head_;
using Base::max_num_arcs_;
using Base::max_num_nodes_;
using Base::num_arcs_;
using Base::num_nodes_;
public:
#if !defined(SWIG)
using Base::end_arc_index;
using Base::Head;
using Base::IsNodeValid;
using Base::kFirstArc;
using Base::kFirstNode;
using Base::kNilArc;
#endif // SWIG
typedef NodeIndexType NodeIndex;
typedef ArcIndexType ArcIndex;
// TODO(user): Configure SWIG to handle the
// CycleHandlerForAnnotatedArcs class.
#if !defined(SWIG)
class CycleHandlerForAnnotatedArcs
: public ArrayIndexCycleHandler<NodeIndexType, ArcIndexType> {
typedef ArrayIndexCycleHandler<NodeIndexType, ArcIndexType> Base;
public:
CycleHandlerForAnnotatedArcs(
PermutationCycleHandler<ArcIndexType>* annotation_handler,
NodeIndexType* data)
: ArrayIndexCycleHandler<NodeIndexType, ArcIndexType>(&data[kFirstArc]),
annotation_handler_(annotation_handler) {}
void SetTempFromIndex(ArcIndexType source) override {
Base::SetTempFromIndex(source);
annotation_handler_->SetTempFromIndex(source);
}
void SetIndexFromIndex(ArcIndexType source,
ArcIndexType destination) const override {
Base::SetIndexFromIndex(source, destination);
annotation_handler_->SetIndexFromIndex(source, destination);
}
void SetIndexFromTemp(ArcIndexType destination) const override {
Base::SetIndexFromTemp(destination);
annotation_handler_->SetIndexFromTemp(destination);
}
private:
PermutationCycleHandler<ArcIndexType>* annotation_handler_;
DISALLOW_COPY_AND_ASSIGN(CycleHandlerForAnnotatedArcs);
};
#endif // SWIG
// Constructor for use by GraphBuilderFromArcs instances and direct
// clients that want to materialize a graph in one step.
// Materializing all at once is the only choice available with a
// static graph.
//
// Args:
// sort_arcs_by_head: determines whether arcs incident to each tail
// node are sorted by head node.
// client_cycle_handler: if non-NULL, mediates the permutation of
// arbitrary annotation data belonging to the client according
// to the permutation applied to the arcs in forming the
// graph. Two permutations may be composed to form the final one
// that affects the arcs. First, the arcs are always permuted to
// group them by tail node because ForwardStaticGraph requires
// this. Second, if each node's outgoing arcs are sorted by head
// node (according to sort_arcs_by_head), that sorting implies
// an additional permutation on the arcs.
ForwardStaticGraph(
const NodeIndexType num_nodes, const ArcIndexType num_arcs,
const bool sort_arcs_by_head,
std::vector<std::pair<NodeIndexType, NodeIndexType> >* client_input_arcs,
// TODO(user): For some reason, SWIG breaks if the
// operations_research namespace is not explicit in the
// following argument declaration.
operations_research::PermutationCycleHandler<ArcIndexType>* const
client_cycle_handler) {
max_num_arcs_ = num_arcs;
num_arcs_ = num_arcs;
max_num_nodes_ = num_nodes;
// A more convenient name for a parameter required by style to be
// a pointer, because we modify its referent.
std::vector<std::pair<NodeIndexType, NodeIndexType> >& input_arcs =
*client_input_arcs;
// We coopt the first_incident_arc_ array as a node-indexed vector
// used for two purposes related to degree before setting up its
// final values. First, it counts the out-degree of each
// node. Second, it is reused to count the number of arcs outgoing
// from each node that have already been put in place from the
// given input_arcs. We reserve an extra entry as a sentinel at
// the end.
first_incident_arc_.Reserve(kFirstNode, kFirstNode + num_nodes);
first_incident_arc_.SetAll(0);
for (ArcIndexType arc = kFirstArc; arc < kFirstArc + num_arcs; ++arc) {
first_incident_arc_[kFirstNode + input_arcs[arc].first] += 1;
// Take this opportunity to see how many nodes are really
// mentioned in the arc list.
num_nodes_ = std::max(
num_nodes_, static_cast<NodeIndexType>(input_arcs[arc].first + 1));
num_nodes_ = std::max(
num_nodes_, static_cast<NodeIndexType>(input_arcs[arc].second + 1));
}
ArcIndexType next_arc = kFirstArc;
for (NodeIndexType node = 0; node < num_nodes; ++node) {
ArcIndexType degree = first_incident_arc_[kFirstNode + node];
first_incident_arc_[kFirstNode + node] = next_arc;
next_arc += degree;
}
DCHECK_EQ(num_arcs, next_arc);
head_.Reserve(kFirstArc, kFirstArc + num_arcs - 1);
std::unique_ptr<ArcIndexType[]> arc_permutation;
if (client_cycle_handler != nullptr) {
arc_permutation.reset(new ArcIndexType[end_arc_index()]);
for (ArcIndexType input_arc = 0; input_arc < num_arcs; ++input_arc) {
NodeIndexType tail = input_arcs[input_arc].first;
NodeIndexType head = input_arcs[input_arc].second;
ArcIndexType arc = first_incident_arc_[kFirstNode + tail];
// The head_ entry will get permuted into the right place
// later.
head_[kFirstArc + input_arc] = kFirstNode + head;
arc_permutation[kFirstArc + arc] = input_arc;
first_incident_arc_[kFirstNode + tail] += 1;
}
} else {
if (sizeof(input_arcs[0].first) >= sizeof(first_incident_arc_[0])) {
// We reuse the input_arcs[].first entries to hold our
// mapping to the head_ array. This allows us to spread out
// cache badness.
for (ArcIndexType input_arc = 0; input_arc < num_arcs; ++input_arc) {
NodeIndexType tail = input_arcs[input_arc].first;
ArcIndexType arc = first_incident_arc_[kFirstNode + tail];
first_incident_arc_[kFirstNode + tail] = arc + 1;
input_arcs[input_arc].first = static_cast<NodeIndexType>(arc);
}
for (ArcIndexType input_arc = 0; input_arc < num_arcs; ++input_arc) {
ArcIndexType arc =
static_cast<ArcIndexType>(input_arcs[input_arc].first);
NodeIndexType head = input_arcs[input_arc].second;
head_[kFirstArc + arc] = kFirstNode + head;
}
} else {
// We cannot reuse the input_arcs[].first entries so we map to
// the head_ array in a single loop.
for (ArcIndexType input_arc = 0; input_arc < num_arcs; ++input_arc) {
NodeIndexType tail = input_arcs[input_arc].first;
NodeIndexType head = input_arcs[input_arc].second;
ArcIndexType arc = first_incident_arc_[kFirstNode + tail];
first_incident_arc_[kFirstNode + tail] = arc + 1;
head_[kFirstArc + arc] = kFirstNode + head;
}
}
}
// Shift the entries in first_incident_arc_ to compensate for the
// counting each one has done through its incident arcs. Note that
// there is a special sentry element at the end of
// first_incident_arc_.
for (NodeIndexType node = kFirstNode + num_nodes; node > /* kFirstNode */ 0;
--node) {
first_incident_arc_[node] = first_incident_arc_[node - 1];
}
first_incident_arc_[kFirstNode] = kFirstArc;
if (sort_arcs_by_head) {
ArcIndexType begin = first_incident_arc_[kFirstNode];
if (client_cycle_handler != nullptr) {
for (NodeIndexType node = 0; node < num_nodes; ++node) {
ArcIndexType end = first_incident_arc_[node + 1];
std::sort(
&arc_permutation[begin], &arc_permutation[end],
PermutationIndexComparisonByArcHead<NodeIndexType, ArcIndexType>(
head_));
begin = end;
}
} else {
for (NodeIndexType node = 0; node < num_nodes; ++node) {
ArcIndexType end = first_incident_arc_[node + 1];
// The second argument in the following has a strange index
// expression because ZVector claims that no index is valid
// unless it refers to an element in the vector. In particular
// an index one past the end is invalid.
ArcIndexType begin_index = (begin < num_arcs ? begin : begin - 1);
ArcIndexType begin_offset = (begin < num_arcs ? 0 : 1);
ArcIndexType end_index = (end > 0 ? end - 1 : end);
ArcIndexType end_offset = (end > 0 ? 1 : 0);
std::sort(&head_[begin_index] + begin_offset,
&head_[end_index] + end_offset);
begin = end;
}
}
}
if (client_cycle_handler != nullptr && num_arcs > 0) {
// Apply the computed permutation if we haven't already.
CycleHandlerForAnnotatedArcs handler_for_constructor(
client_cycle_handler, &head_[kFirstArc] - kFirstArc);
// We use a permutation cycle handler to place the head array
// indices and permute the client's arc annotation data along
// with them.
PermutationApplier<ArcIndexType> permutation(&handler_for_constructor);
permutation.Apply(&arc_permutation[0], kFirstArc, end_arc_index());
}
}
// Returns the tail or start-node of arc.
NodeIndexType Tail(const ArcIndexType arc) const {
DCHECK(CheckArcValidity(arc));
DCHECK(CheckTailIndexValidity(arc));
return (*tail_)[arc];
}
// Returns true if arc is incoming to node.
bool IsIncoming(ArcIndexType arc, NodeIndexType node) const {
return Head(arc) == node;
}
// Utility function to check that an arc index is within the bounds.
// It is exported so that users of the ForwardStaticGraph class can use it.
// To be used in a DCHECK.
bool CheckArcBounds(const ArcIndexType arc) const {
return ((arc == kNilArc) || (arc >= kFirstArc && arc < max_num_arcs_));
}
// Utility function to check that an arc index is within the bounds AND
// different from kNilArc.
// It is exported so that users of the ForwardStaticGraph class can use it.
// To be used in a DCHECK.
bool CheckArcValidity(const ArcIndexType arc) const {
return ((arc != kNilArc) && (arc >= kFirstArc && arc < max_num_arcs_));
}
// Returns true if arc is a valid index into the (*tail_) array.
bool CheckTailIndexValidity(const ArcIndexType arc) const {
return ((tail_ != nullptr) && (arc >= kFirstArc) &&
(arc <= tail_->max_index()));
}
ArcIndexType NextOutgoingArc(const NodeIndexType node,
ArcIndexType arc) const {
DCHECK(IsNodeValid(node));
DCHECK(CheckArcValidity(arc));
++arc;
if (arc < first_incident_arc_[node + 1]) {
return arc;
} else {
return kNilArc;
}
}
// Returns a debug string containing all the information contained in the
// data structure in raw form.
std::string DebugString() const {
std::string result = "Arcs:(node) :\n";
for (ArcIndexType arc = kFirstArc; arc < num_arcs_; ++arc) {
result += " " + ArcDebugString(arc) + ":(" + NodeDebugString(head_[arc]) +
")\n";
}
result += "Node:First arc :\n";
for (NodeIndexType node = kFirstNode; node <= num_nodes_; ++node) {
result += " " + NodeDebugString(node) + ":" +
ArcDebugString(first_incident_arc_[node]) + "\n";
}
return result;
}
bool BuildTailArray() {
// If (*tail_) is already allocated, we have the invariant that
// its contents are canonical, so we do not need to do anything
// here in that case except return true.
if (tail_ == nullptr) {
if (!RepresentationClean()) {
// We have been asked to build the (*tail_) array, but we have
// no valid information from which to build it. The graph is
// in an unrecoverable, inconsistent state.
return false;
}
// Reallocate (*tail_) and rebuild its contents from the
// adjacency lists.
tail_.reset(new ZVector<NodeIndexType>);
tail_->Reserve(kFirstArc, max_num_arcs_ - 1);
typename Base::NodeIterator node_it(*this);
for (; node_it.Ok(); node_it.Next()) {
NodeIndexType node = node_it.Index();
typename Base::OutgoingArcIterator arc_it(*this, node);
for (; arc_it.Ok(); arc_it.Next()) {
(*tail_)[arc_it.Index()] = node;
}
}
}
DCHECK(TailArrayComplete());
return true;
}
void ReleaseTailArray() { tail_.reset(nullptr); }
// To be used in a DCHECK().
bool TailArrayComplete() const {
CHECK(tail_);
for (ArcIndexType arc = kFirstArc; arc < num_arcs_; ++arc) {
CHECK(CheckTailIndexValidity(arc));
CHECK(IsNodeValid((*tail_)[arc]));
}
return true;
}
private:
bool IsDirect() const { return true; }
bool RepresentationClean() const { return true; }
bool IsOutgoing(const NodeIndexType node,
const ArcIndexType unused_arc) const {
return true;
}
// Returns the first arc in node's incidence list.
ArcIndexType FirstOutgoingOrOppositeIncomingArc(NodeIndexType node) const {
DCHECK(RepresentationClean());
DCHECK(IsNodeValid(node));
ArcIndexType result = first_incident_arc_[node];
return ((result != first_incident_arc_[node + 1]) ? result : kNilArc);
}
// Utility method that finds the next outgoing arc.
ArcIndexType FindNextOutgoingArc(ArcIndexType arc) const {
DCHECK(CheckArcBounds(arc));
return arc;
}
// Array of node indices, not always present. (*tail_)[i] contains
// the tail node of arc i. This array is not needed for normal graph
// traversal operations, but is used in optimizing the graph's
// layout so arcs are grouped by tail node, and can be used in one
// approach to serializing the graph.
//
// Invariants: At any time when we are not executing a method of
// this class, either tail_ == NULL or the tail_ array's contents
// are kept canonical. If tail_ != NULL, any method that modifies
// adjacency lists must also ensure (*tail_) is modified
// correspondingly. The converse does not hold: Modifications to
// (*tail_) are allowed without updating the adjacency lists. If
// such modifications take place, representation_clean_ must be set
// to false, of course, to indicate that the adjacency lists are no
// longer current.
std::unique_ptr<ZVector<NodeIndexType> > tail_;
};
// The index of the 'nil' node in the graph.
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
const NodeIndexType
StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph>::kNilNode = -1;
// The index of the 'nil' arc in the graph.
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
const ArcIndexType
StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph>::kNilArc =
std::numeric_limits<ArcIndexType>::min();
// The index of the first node in the graph.
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
const NodeIndexType
StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph>::kFirstNode = 0;
// The index of the first arc in the graph.
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
const ArcIndexType
StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph>::kFirstArc = 0;
// The maximum possible node index in the graph.
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
const NodeIndexType
StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph>::kMaxNumNodes =
std::numeric_limits<NodeIndexType>::max();
// The maximum possible number of arcs in the graph.
// (The maximum index is kMaxNumArcs-1, since indices start at 0.)
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
const ArcIndexType
StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph>::kMaxNumArcs =
std::numeric_limits<ArcIndexType>::max();
// A template for the base class that holds the functionality that exists in
// common between the EbertGraph<> template and the ForwardEbertGraph<>
// template.
//
// This template is for internal use only, and this is enforced by making all
// constructors for this class template protected. Clients should use one of the
// two derived-class templates. Most clients will not even use those directly,
// but will use the StarGraph and ForwardStarGraph typenames declared above.
//
// The DerivedGraph template argument must be the type of the class (typically
// itself built from a template) that:
// 1. implements the full interface expected for either ForwardEbertGraph or
// EbertGraph, and
// 2. inherits from an instance of this template.
// The base class needs access to some members of the derived class such as, for
// example, NextOutgoingArc(), and it gets this access via the DerivedGraph
// template argument.
template <typename NodeIndexType, typename ArcIndexType, typename DerivedGraph>
class EbertGraphBase
: public StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph> {
typedef StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph> Base;
friend class StarGraphBase<NodeIndexType, ArcIndexType, DerivedGraph>;
protected:
using Base::first_incident_arc_;
using Base::head_;
using Base::max_num_arcs_;
using Base::max_num_nodes_;
using Base::num_arcs_;
using Base::num_nodes_;
public:
#if !SWIG
using Base::end_arc_index;
using Base::IsNodeValid;
using Base::kFirstArc;
using Base::kFirstNode;
using Base::kMaxNumArcs;
using Base::kMaxNumNodes;
using Base::kNilArc;
using Base::kNilNode;
#endif // SWIG
// Reserves memory needed for max_num_nodes nodes and max_num_arcs arcs.
// Returns false if the parameters passed are not OK.
// It can be used to enlarge the graph, but does not shrink memory
// if called with smaller values.
bool Reserve(NodeIndexType new_max_num_nodes, ArcIndexType new_max_num_arcs) {
if (new_max_num_nodes < 0 || new_max_num_nodes > kMaxNumNodes) {
return false;
}
if (new_max_num_arcs < 0 || new_max_num_arcs > kMaxNumArcs) {
return false;
}
first_incident_arc_.Reserve(kFirstNode, new_max_num_nodes - 1);
for (NodeIndexType node = max_num_nodes_;
node <= first_incident_arc_.max_index(); ++node) {
first_incident_arc_.Set(node, kNilArc);
}
ThisAsDerived()->ReserveInternal(new_max_num_nodes, new_max_num_arcs);
max_num_nodes_ = new_max_num_nodes;
max_num_arcs_ = new_max_num_arcs;
return true;
}
// Adds an arc to the graph and returns its index.
// Returns kNilArc if the arc could not be added.
// Note that for a given pair (tail, head) AddArc does not overwrite an
// already-existing arc between tail and head: Another arc is created
// instead. This makes it possible to handle multi-graphs.