OR-Tools  9.2
topologicalsorter.h
Go to the documentation of this file.
1 // Copyright 2010-2021 Google LLC
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 // TopologicalSorter provides topologically sorted traversal of the
15 // nodes of a directed acyclic graph (DAG) with up to INT_MAX nodes.
16 // It sorts ancestor nodes before their descendants.
17 //
18 // If your graph is not a DAG and you're reading this, you are probably
19 // looking for ortools/graph/strongly_connected_components.h which does
20 // the topological decomposition of a directed graph.
21 //
22 // EXAMPLE:
23 //
24 // vector<int> result;
25 // vector<string> nodes = {"a", "b", "c"};
26 // vector<pair<string, string>> arcs = {{"a", "c"}, {"a", "b"}, {"b", "c"}};
27 // if (util::StableTopologicalSort(num_nodes, arcs, &result)) {
28 // LOG(INFO) << "The topological order is: " << gtl::LogContainer(result);
29 // } else {
30 // LOG(INFO) << "The graph is cyclic.";
31 // // Note: you can extract a cycle with the TopologicalSorter class, or
32 // // with the API defined in circularity_detector.h.
33 // }
34 // // This will be successful and result will be equal to {"a", "b", "c"}.
35 //
36 // There are 8 flavors of topological sort, from these 3 bits:
37 // - There are OrDie() versions that directly return the topological order, or
38 // crash if a cycle is detected (and LOG the cycle).
39 // - There are type-generic versions that can take any node type (including
40 // non-dense integers), but slower, or the "dense int" versions which requires
41 // nodes to be a dense interval [0..num_nodes-1]. Note that the type must
42 // be compatible with LOG << T if you're using the OrDie() version.
43 // - The sorting can be either stable or not. "Stable" essentially means that it
44 // will preserve the order of nodes, if possible. More precisely, the returned
45 // topological order will be the lexicographically minimal valid order, where
46 // "lexicographic" applies to the indices of the nodes.
47 //
48 // TopologicalSort()
49 // TopologicalSortOrDie()
50 // StableTopologicalSort()
51 // StableTopologicalSortOrDie()
52 // DenseIntTopologicalSort()
53 // DenseIntTopologicalSortOrDie()
54 // DenseIntStableTopologicalSort()
55 // DenseIntStableTopologicalSortOrDie()
56 //
57 // If you need more control, or a step-by-step topological sort, see the
58 // TopologicalSorter classes below.
59 
60 #ifndef UTIL_GRAPH_TOPOLOGICALSORTER_H__
61 #define UTIL_GRAPH_TOPOLOGICALSORTER_H__
62 
63 #include <queue>
64 #include <type_traits>
65 #include <vector>
66 
67 #include "absl/base/attributes.h"
68 #include "absl/container/flat_hash_map.h"
70 #include "ortools/base/logging.h"
71 #include "ortools/base/macros.h"
72 #include "ortools/base/map_util.h"
73 #include "ortools/base/stl_util.h"
74 
75 namespace util {
76 
77 // Returns true if the graph was a DAG, and outputs the topological order in
78 // "topological_order". Returns false if the graph is cyclic.
79 // Works in O(num_nodes + arcs.size()), and is pretty fast.
80 inline ABSL_MUST_USE_RESULT bool DenseIntTopologicalSort(
81  int num_nodes, const std::vector<std::pair<int, int>>& arcs,
82  std::vector<int>* topological_order);
83 
84 // Like DenseIntTopologicalSort, but stable.
85 inline ABSL_MUST_USE_RESULT bool DenseIntStableTopologicalSort(
86  int num_nodes, const std::vector<std::pair<int, int>>& arcs,
87  std::vector<int>* topological_order);
88 
89 // Finds a cycle in the directed graph given as argument: nodes are dense
90 // integers in 0..num_nodes-1, and (directed) arcs are pairs of nodes
91 // {from, to}.
92 // The returned cycle is a list of nodes that form a cycle, eg. {1, 4, 3}
93 // if the cycle 1->4->3->1 exists.
94 // If the graph is acyclic, returns an empty vector.
95 ABSL_MUST_USE_RESULT std::vector<int> FindCycleInDenseIntGraph(
96  int num_nodes, const std::vector<std::pair<int, int>>& arcs);
97 
98 // Like the two above, but with generic node types. The nodes must be provided.
99 // Can be significantly slower, but still linear.
100 template <typename T>
101 ABSL_MUST_USE_RESULT bool TopologicalSort(
102  const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs,
103  std::vector<T>* topological_order);
104 template <typename T>
105 ABSL_MUST_USE_RESULT bool StableTopologicalSort(
106  const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs,
107  std::vector<T>* topological_order);
108 
109 // "OrDie()" versions of the 4 functions above. Those directly return the
110 // topological order, which makes their API even simpler.
111 inline std::vector<int> DenseIntTopologicalSortOrDie(
112  int num_nodes, const std::vector<std::pair<int, int>>& arcs);
113 inline std::vector<int> DenseIntStableTopologicalSortOrDie(
114  int num_nodes, const std::vector<std::pair<int, int>>& arcs);
115 template <typename T>
116 std::vector<T> TopologicalSortOrDie(const std::vector<T>& nodes,
117  const std::vector<std::pair<T, T>>& arcs);
118 template <typename T>
119 std::vector<T> StableTopologicalSortOrDie(
120  const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs);
121 
122 namespace internal {
123 // Internal wrapper around the *TopologicalSort classes.
124 template <typename T, typename Sorter>
125 ABSL_MUST_USE_RESULT bool RunTopologicalSorter(
126  Sorter* sorter, const std::vector<std::pair<T, T>>& arcs,
127  std::vector<T>* topological_order_or_cycle);
128 
129 // Do not use the templated class directly, instead use one of the
130 // typedefs DenseIntTopologicalSorter or DenseIntStableTopologicalSorter.
131 //
132 // The equivalent of a TopologicalSorter<int> which nodes are the
133 // N integers from 0 to N-1 (see the toplevel comment). The API is
134 // exactly similar to that of TopologicalSorter, please refer to the
135 // TopologicalSorter class below for more detailed comments.
136 //
137 // If the template parameter is true then the sort will be stable.
138 // This means that the order of the nodes will be maintained as much as
139 // possible. A non-stable sort is more efficient, since the complexity
140 // of getting the next node is O(1) rather than O(log(Nodes)).
141 template <bool stable_sort = false>
143  public:
144  // To store the adjacency lists efficiently.
145  typedef std::vector<int> AdjacencyList;
146 
147  // For efficiency, it is best to specify how many nodes are required
148  // by using the next constructor.
150  : traversal_started_(false),
151  num_edges_(0),
152  num_edges_added_since_last_duplicate_removal_(0) {}
153 
154  // One may also construct a DenseIntTopologicalSorterTpl with a predefined
155  // number of empty nodes. One can thus bypass the AddNode() API,
156  // which may yield a lower memory usage.
157  explicit DenseIntTopologicalSorterTpl(int num_nodes)
158  : adjacency_lists_(num_nodes),
159  traversal_started_(false),
160  num_edges_(0),
161  num_edges_added_since_last_duplicate_removal_(0) {}
162 
163  // Performs in constant amortized time. Calling this will make all
164  // node indices in [0 .. node_index] be valid node indices. If you
165  // can avoid using AddNode(), you should! If you know the number of
166  // nodes in advance, you should specify that at construction time --
167  // it will be faster and use less memory.
168  void AddNode(int node_index);
169 
170  // Performs in constant amortized time. Calling this will make all
171  // node indices in [0, max(from, to)] be valid node indices.
172  void AddEdge(int from, int to);
173 
174  // Performs in O(average degree) in average. If a cycle is detected
175  // and "output_cycle_nodes" isn't NULL, it will require an additional
176  // O(number of edges + number of nodes in the graph) time.
177  bool GetNext(int* next_node_index, bool* cyclic,
178  std::vector<int>* output_cycle_nodes = NULL);
179 
181  StartTraversal();
182  return nodes_with_zero_indegree_.size();
183  }
184 
185  void StartTraversal();
186 
187  bool TraversalStarted() const { return traversal_started_; }
188 
189  // Given a vector<AdjacencyList> of size n such that elements of the
190  // AdjacencyList are in [0, n-1], remove the duplicates within each
191  // AdjacencyList of size greater or equal to skip_lists_smaller_than,
192  // in linear time. Returns the total number of duplicates removed.
193  // This method is exposed for unit testing purposes only.
194  static int RemoveDuplicates(std::vector<AdjacencyList>* lists,
195  int skip_lists_smaller_than);
196 
197  // To extract a cycle. When there is no cycle, cycle_nodes will be empty.
198  void ExtractCycle(std::vector<int>* cycle_nodes) const;
199 
200  private:
201  // Outgoing adjacency lists.
202  std::vector<AdjacencyList> adjacency_lists_;
203 
204  bool traversal_started_;
205 
206  // Only valid after a traversal started.
207  int num_nodes_left_;
208  typename std::conditional<
209  stable_sort,
210  // We use greater<int> so that the lowest elements gets popped first.
211  std::priority_queue<int, std::vector<int>, std::greater<int>>,
212  std::queue<int>>::type nodes_with_zero_indegree_;
213  std::vector<int> indegree_;
214 
215  // Used internally by AddEdge() to decide whether to trigger
216  // RemoveDuplicates(). See the .cc.
217  int num_edges_; // current total number of edges.
218  int num_edges_added_since_last_duplicate_removal_;
219 
220  private:
221  DISALLOW_COPY_AND_ASSIGN(DenseIntTopologicalSorterTpl);
222 };
223 
224 extern template class DenseIntTopologicalSorterTpl<false>;
225 extern template class DenseIntTopologicalSorterTpl<true>;
226 
227 } // namespace internal
228 
229 // Recommended version for general usage. The stability makes it more
230 // deterministic, and its behavior is guaranteed to never change.
231 typedef ::util::internal::DenseIntTopologicalSorterTpl<
232  /*stable_sort=*/true>
234 
235 // Use this version if you are certain you don't care about the
236 // tie-breaking order and need the 5 to 10% performance gain. The
237 // performance gain can be more significant for large graphs with large
238 // numbers of source nodes (for example 2 Million nodes with 2 Million
239 // random edges sees a factor of 0.7 difference in completion time).
240 typedef ::util::internal::DenseIntTopologicalSorterTpl<
241  /*stable_sort=*/false>
243 
244 // A copy of each Node is stored internally. Duplicated edges are allowed,
245 // and discarded lazily so that AddEdge() keeps an amortized constant
246 // time, yet the total memory usage remains O(number of different edges +
247 // number of nodes).
248 //
249 // DenseIntTopologicalSorter implements the core topological sort
250 // algorithm. For greater efficiency it can be used directly
251 // (TopologicalSorter<int> is about 1.5-3x slower).
252 //
253 // TopologicalSorter requires that all nodes and edges be added before
254 // traversing the nodes, otherwise it will die with a fatal error.
255 //
256 //
257 // Note(user): since all the real work is done by
258 // DenseIntTopologicalSorterTpl, and this class is a template, we inline
259 // every function here in the .h.
260 //
261 // If stable_sort is true then the topological sort will preserve the
262 // original order of the nodes as much as possible. Note, the order
263 // which is preserved is the order in which the nodes are added (if you
264 // use AddEdge it will add the first argument and then the second).
265 template <typename T, bool stable_sort = false,
266  typename Hash = typename absl::flat_hash_map<T, int>::hasher,
267  typename KeyEqual =
268  typename absl::flat_hash_map<T, int, Hash>::key_equal>
270  public:
273 
274  // Adds a node to the graph, if it has not already been added via
275  // previous calls to AddNode()/AddEdge(). If no edges are later
276  // added connecting this node, then it remains an isolated node in
277  // the graph. AddNode() only exists to support isolated nodes. There
278  // is no requirement (nor is it an error) to call AddNode() for the
279  // endpoints used in a call to AddEdge(). Dies with a fatal error if
280  // called after a traversal has been started (see TraversalStarted()),
281  // or if more than INT_MAX nodes are being added.
282  void AddNode(const T& node) { int_sorter_.AddNode(LookupOrInsertNode(node)); }
283 
284  // Adds a directed edge with the given endpoints to the graph. There
285  // is no requirement (nor is it an error) to call AddNode() for the
286  // endpoints. Dies with a fatal error if called after a traversal
287  // has been started (see TraversalStarted()).
288  void AddEdge(const T& from, const T& to) {
289  // The lookups are not inlined into AddEdge because we need to ensure that
290  // "from" is inserted before "to".
291  const int from_int = LookupOrInsertNode(from);
292  const int to_int = LookupOrInsertNode(to);
293  int_sorter_.AddEdge(from_int, to_int);
294  }
295 
296  // Visits the least node in topological order over the current set of
297  // nodes and edges, and marks that node as visited, so that repeated
298  // calls to GetNext() will visit all nodes in order. Writes the newly
299  // visited node in *node and returns true with *cyclic set to false
300  // (assuming the graph has not yet been discovered to be cyclic).
301  // Returns false if all nodes have been visited, or if the graph is
302  // discovered to be cyclic, in which case *cyclic is also set to true.
303  //
304  // If you set the optional argument "output_cycle_nodes" to non-NULL and
305  // a cycle is detected, it will dump an arbitrary cycle of the graph
306  // (whose length will be between 1 and #number_of_nodes, inclusive),
307  // in the natural order: for example if "output_cycle_nodes" is filled
308  // with ["A", "C", "B"], it means that A->C->B->A is a directed cycle
309  // of the graph.
310  //
311  // This starts a traversal (if not started already). Note that the
312  // graph can only be traversed once.
313  bool GetNext(T* node, bool* cyclic_ptr,
314  std::vector<T>* output_cycle_nodes = NULL) {
315  StartTraversal();
316  int node_index;
317  if (!int_sorter_.GetNext(&node_index, cyclic_ptr,
318  output_cycle_nodes ? &cycle_int_nodes_ : NULL)) {
319  if (*cyclic_ptr && output_cycle_nodes != NULL) {
320  output_cycle_nodes->clear();
321  for (const int int_node : cycle_int_nodes_) {
322  output_cycle_nodes->push_back(nodes_[int_node]);
323  }
324  }
325  return false;
326  }
327  *node = nodes_[node_index];
328  return true;
329  }
330 
331  // Returns the number of nodes that currently have zero indegree.
332  // This starts a traversal (if not started already).
334  StartTraversal();
335  return int_sorter_.GetCurrentFringeSize();
336  }
337 
338  // Start a traversal. See TraversalStarted(). This initializes the
339  // various data structures of the sorter. Since this takes O(num_nodes
340  // + num_edges) time, users may want to call this at their convenience,
341  // instead of making it happen with the first GetNext().
342  void StartTraversal() {
343  if (TraversalStarted()) return;
344  nodes_.resize(node_to_index_.size());
345  // We move elements from the absl::flat_hash_map to this vector, without
346  // extra copy (if they are movable).
347  for (auto& node_and_index : node_to_index_) {
348  nodes_[node_and_index.second] = std::move(node_and_index.first);
349  }
350  gtl::STLClearHashIfBig(&node_to_index_, 1 << 16);
351  int_sorter_.StartTraversal();
352  }
353 
354  // Whether a traversal has started. If true, AddNode() and AddEdge()
355  // can no longer be called.
356  bool TraversalStarted() const { return int_sorter_.TraversalStarted(); }
357 
358  private:
359  // A simple mapping from node to their dense index, in 0..num_nodes-1,
360  // which will be their index in nodes_[]. Cleared when a traversal
361  // starts, and replaced by nodes_[].
362  absl::flat_hash_map<T, int, Hash, KeyEqual> node_to_index_;
363 
364  // Stores all the nodes as soon as a traversal starts.
365  std::vector<T> nodes_;
366 
367  // An internal DenseIntTopologicalSorterTpl that does all the real work.
369 
370  // Used internally to extract cycles from the underlying
371  // DenseIntTopologicalSorterTpl.
372  std::vector<int> cycle_int_nodes_;
373 
374  // Lookup an existing node's index, or add the node and return the
375  // new index that was assigned to it.
376  int LookupOrInsertNode(const T& node) {
377  return gtl::LookupOrInsert(&node_to_index_, node, node_to_index_.size());
378  }
379 
380  DISALLOW_COPY_AND_ASSIGN(TopologicalSorter);
381 };
382 
383 namespace internal {
384 // If successful, returns true and outputs the order in "topological_order".
385 // If not, returns false and outputs a cycle in "cycle" (if not null).
386 template <typename T, typename Sorter>
387 ABSL_MUST_USE_RESULT bool RunTopologicalSorter(
388  Sorter* sorter, const std::vector<std::pair<T, T>>& arcs,
389  std::vector<T>* topological_order, std::vector<T>* cycle) {
390  topological_order->clear();
391  for (const auto& arc : arcs) {
392  sorter->AddEdge(arc.first, arc.second);
393  }
394  bool cyclic = false;
395  sorter->StartTraversal();
396  T next;
397  while (sorter->GetNext(&next, &cyclic, cycle)) {
398  topological_order->push_back(next);
399  }
400  return !cyclic;
401 }
402 
403 template <bool stable_sort = false>
404 ABSL_MUST_USE_RESULT bool DenseIntTopologicalSortImpl(
405  int num_nodes, const std::vector<std::pair<int, int>>& arcs,
406  std::vector<int>* topological_order) {
408  return RunTopologicalSorter<int, decltype(sorter)>(
409  &sorter, arcs, topological_order, nullptr);
410 }
411 
412 template <typename T, bool stable_sort = false>
413 ABSL_MUST_USE_RESULT bool TopologicalSortImpl(
414  const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs,
415  std::vector<T>* topological_order) {
417  for (const T& node : nodes) {
418  sorter.AddNode(node);
419  }
420  return RunTopologicalSorter<T, decltype(sorter)>(&sorter, arcs,
421  topological_order, nullptr);
422 }
423 
424 // Now, the OrDie() versions, which directly return the topological order.
425 template <typename T, typename Sorter>
427  Sorter* sorter, const std::vector<std::pair<T, T>>& arcs) {
428  std::vector<T> topo_order;
429  CHECK(RunTopologicalSorter(sorter, arcs, &topo_order, &topo_order))
430  << "Found cycle: " << gtl::LogContainer(topo_order);
431  return topo_order;
432 }
433 
434 template <bool stable_sort = false>
436  int num_nodes, const std::vector<std::pair<int, int>>& arcs) {
438  return RunTopologicalSorterOrDie(&sorter, arcs);
439 }
440 
441 template <typename T, bool stable_sort = false>
443  const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs) {
445  for (const T& node : nodes) {
446  sorter.AddNode(node);
447  }
448  return RunTopologicalSorterOrDie(&sorter, arcs);
449 }
450 } // namespace internal
451 
452 // Implementations of the "simple API" functions declared at the top.
454  int num_nodes, const std::vector<std::pair<int, int>>& arcs,
455  std::vector<int>* topological_order) {
456  return internal::DenseIntTopologicalSortImpl<false>(num_nodes, arcs,
457  topological_order);
458 }
459 
461  int num_nodes, const std::vector<std::pair<int, int>>& arcs,
462  std::vector<int>* topological_order) {
463  return internal::DenseIntTopologicalSortImpl<true>(num_nodes, arcs,
464  topological_order);
465 }
466 
467 template <typename T>
468 bool TopologicalSort(const std::vector<T>& nodes,
469  const std::vector<std::pair<T, T>>& arcs,
470  std::vector<T>* topological_order) {
471  return internal::TopologicalSortImpl<T, false>(nodes, arcs,
472  topological_order);
473 }
474 
475 template <typename T>
476 bool StableTopologicalSort(const std::vector<T>& nodes,
477  const std::vector<std::pair<T, T>>& arcs,
478  std::vector<T>* topological_order) {
479  return internal::TopologicalSortImpl<T, true>(nodes, arcs, topological_order);
480 }
481 
482 inline std::vector<int> DenseIntTopologicalSortOrDie(
483  int num_nodes, const std::vector<std::pair<int, int>>& arcs) {
484  return internal::DenseIntTopologicalSortOrDieImpl<false>(num_nodes, arcs);
485 }
486 
487 inline std::vector<int> DenseIntStableTopologicalSortOrDie(
488  int num_nodes, const std::vector<std::pair<int, int>>& arcs) {
489  return internal::DenseIntTopologicalSortOrDieImpl<true>(num_nodes, arcs);
490 }
491 
492 template <typename T>
493 std::vector<T> TopologicalSortOrDie(const std::vector<T>& nodes,
494  const std::vector<std::pair<T, T>>& arcs) {
495  return internal::TopologicalSortOrDieImpl<T, false>(nodes, arcs);
496 }
497 
498 template <typename T>
500  const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs) {
501  return internal::TopologicalSortOrDieImpl<T, true>(nodes, arcs);
502 }
503 
504 } // namespace util
505 
506 // BACKWARDS COMPATIBILITY
507 // Some of the classes or functions have been exposed under the global namespace
508 // or the util::graph:: namespace. Until all clients are fixed to use the
509 // util:: namespace, we keep those versions around.
512 template <typename T, bool stable_sort = false,
513  typename Hash = typename absl::flat_hash_map<T, int>::hasher,
514  typename KeyEqual =
515  typename absl::flat_hash_map<T, int, Hash>::key_equal>
517  : public ::util::TopologicalSorter<T, stable_sort, Hash, KeyEqual> {};
518 
519 namespace util {
520 namespace graph {
521 inline std::vector<int> DenseIntTopologicalSortOrDie(
522  int num_nodes, const std::vector<std::pair<int, int>>& arcs) {
524 }
525 inline std::vector<int> DenseIntStableTopologicalSortOrDie(
526  int num_nodes, const std::vector<std::pair<int, int>>& arcs) {
528 }
529 template <typename T>
531  const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs) {
532  return ::util::StableTopologicalSortOrDie<T>(nodes, arcs);
533 }
534 
535 } // namespace graph
536 } // namespace util
537 
538 #endif // UTIL_GRAPH_TOPOLOGICALSORTER_H__
uint64_t Hash(uint64_t num, uint64_t c)
Definition: hash.h:150
#define CHECK(condition)
Definition: base/logging.h:495
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
std::vector< int > DenseIntTopologicalSortOrDieImpl(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
ABSL_MUST_USE_RESULT bool TopologicalSortImpl(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs, std::vector< T > *topological_order)
ABSL_MUST_USE_RESULT bool DenseIntTopologicalSortImpl(int num_nodes, const std::vector< std::pair< int, int >> &arcs, std::vector< int > *topological_order)
::util::DenseIntTopologicalSorter DenseIntTopologicalSorter
bool GetNext(int *next_node_index, bool *cyclic, std::vector< int > *output_cycle_nodes=NULL)
std::vector< T > RunTopologicalSorterOrDie(Sorter *sorter, const std::vector< std::pair< T, T >> &arcs)
::util::DenseIntStableTopologicalSorter DenseIntStableTopologicalSorter
void STLClearHashIfBig(T *obj, size_t limit)
Definition: stl_util.h:180
ABSL_MUST_USE_RESULT bool RunTopologicalSorter(Sorter *sorter, const std::vector< std::pair< T, T >> &arcs, std::vector< T > *topological_order_or_cycle)
std::vector< T > TopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
Block * next
void ExtractCycle(std::vector< int > *cycle_nodes) const
std::vector< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
auto LogContainer(const ContainerT &container, const PolicyT &policy) -> decltype(gtl::LogRange(container.begin(), container.end(), policy))
std::vector< int > FindCycleInDenseIntGraph(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
void AddNode(const T &node)
ABSL_MUST_USE_RESULT bool DenseIntTopologicalSort(int num_nodes, const std::vector< std::pair< int, int >> &arcs, std::vector< int > *topological_order)
bool GetNext(T *node, bool *cyclic_ptr, std::vector< T > *output_cycle_nodes=NULL)
std::vector< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
static int RemoveDuplicates(std::vector< AdjacencyList > *lists, int skip_lists_smaller_than)
ABSL_MUST_USE_RESULT bool TopologicalSort(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs, std::vector< T > *topological_order)
std::vector< T > TopologicalSortOrDieImpl(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
::util::internal::DenseIntTopologicalSorterTpl< true > DenseIntStableTopologicalSorter
Collection::value_type::second_type & LookupOrInsert(Collection *const collection, const typename Collection::value_type::first_type &key, const typename Collection::value_type::second_type &value)
Definition: map_util.h:237
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
::util::internal::DenseIntTopologicalSorterTpl< false > DenseIntTopologicalSorter
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
int nodes
ABSL_MUST_USE_RESULT bool DenseIntStableTopologicalSort(int num_nodes, const std::vector< std::pair< int, int >> &arcs, std::vector< int > *topological_order)
void AddEdge(const T &from, const T &to)
ABSL_MUST_USE_RESULT bool StableTopologicalSort(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs, std::vector< T > *topological_order)