Google OR-Tools: ortools/graph/topologicalsorter.h Source File
30#ifndef UTIL_GRAPH_TOPOLOGICALSORTER_H__
31#define UTIL_GRAPH_TOPOLOGICALSORTER_H__
41#include "absl/base/attributes.h"
42#include "absl/container/flat_hash_map.h"
43#include "absl/container/inlined_vector.h"
44#include "absl/status/status.h"
45#include "absl/status/statusor.h"
46#include "absl/strings/str_format.h"
47#include "absl/types/span.h"
55namespace util {
90template <class AdjacencyLists>
92 std::vector<typename util::GraphTraits<AdjacencyLists>::NodeIndex>>
101template <class AdjacencyLists>
103 std::vector<typename util::GraphTraits<AdjacencyLists>::NodeIndex>>
121 const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs,
122 std::vector<T>* topological_order);
126 const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs,
127 std::vector<T>* topological_order, std::vector<T>* cycle);
131 const std::vector<std::pair<T, T>>& arcs);
138 const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs,
139 std::vector<T>* topological_order);
143 const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs,
144 std::vector<T>* topological_order, std::vector<T>* cycle);
148 const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs);
168 int num_nodes, const std::vector<std::pair<int, int>>& arcs,
169 std::vector<int>* topological_order);
171 int num_nodes, const std::vector<std::pair<int, int>>& arcs);
173 int num_nodes, const std::vector<std::pair<int, int>>& arcs,
174 std::vector<int>* topological_order);
176 int num_nodes, const std::vector<std::pair<int, int>>& arcs);
180template <typename T, typename Sorter>
182 Sorter* sorter, const std::vector<std::pair<T, T>>& arcs,
183 std::vector<T>* topological_order_or_cycle);
197template <bool stable_sort = false>
232 void AddEdges(absl::Span<const std::pair<int, int>> edges);
243 bool GetNext(int* next_node_index, bool* cyclic,
244 std::vector<int>* output_cycle_nodes = nullptr);
261 int skip_lists_smaller_than);
268 std::vector<AdjacencyList> adjacency_lists_;
274 typename std::conditional<
277 std::priority_queue<int, std::vector<int>, std::greater<int>>,
278 std::queue<int>>::type nodes_with_zero_indegree_;
279 std::vector<int> indegree_;
327template <typename T, bool stable_sort = false,
328 typename Hash = typename absl::flat_hash_map<T, int>::hasher,
330 typename absl::flat_hash_map<T, int, Hash>::key_equal>
348 void AddNode(const T& node) { int_sorter_.AddNode(LookupOrInsertNode(node)); }
351 void AddEdges(const std::vector<std::pair<T, T>>& edges) {
362 const int from_int = LookupOrInsertNode(from);
363 const int to_int = LookupOrInsertNode(to);
384 bool GetNext(T* node, bool* cyclic_ptr,
385 std::vector<T>* output_cycle_nodes = nullptr) {
390 output_cycle_nodes ? &cycle_int_nodes_ : nullptr)) {
391 if (*cyclic_ptr && output_cycle_nodes != nullptr) {
392 output_cycle_nodes->clear();
393 for (const int int_node : cycle_int_nodes_) {
394 output_cycle_nodes->push_back(nodes_[int_node]);
416 nodes_.resize(node_to_index_.size());
419 for (auto& node_and_index : node_to_index_) {
420 nodes_[node_and_index.second] = std::move(node_and_index.first);
434 absl::flat_hash_map<T, int, Hash, KeyEqual> node_to_index_;
444 std::vector<int> cycle_int_nodes_;
448 int LookupOrInsertNode(const T& node) {
449 return gtl::LookupOrInsert(&node_to_index_, node, node_to_index_.size());
456template <typename T, typename Sorter>
458 Sorter* sorter, const std::vector<std::pair<T, T>>& arcs,
459 std::vector<T>* topological_order, std::vector<T>* cycle) {
460 topological_order->clear();
465 while (sorter->GetNext(&next, &cyclic, cycle)) {
471template <bool stable_sort = false>
473 int num_nodes, const std::vector<std::pair<int, int>>& arcs,
474 std::vector<int>* topological_order) {
476 topological_order->reserve(num_nodes);
481template <typename T, bool stable_sort = false>
483 absl::Span<const T> nodes, const std::vector<std::pair<T, T>>& arcs,
484 std::vector<T>* topological_order, std::vector<T>* cycle) {
486 for (const T& node : nodes) {
494template <typename T, typename Sorter>
496 Sorter* sorter, int num_nodes, const std::vector<std::pair<T, T>>& arcs) {
497 std::vector<T> topo_order;
504template <bool stable_sort = false>
511template <typename T, bool stable_sort = false>
513 const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs) {
524 int num_nodes, const std::vector<std::pair<int, int>>& arcs,
531 int num_nodes, const std::vector<std::pair<int, int>>& arcs,
547 const std::vector<std::pair<T, T>>& arcs,
548 std::vector<T>* topological_order, std::vector<T>* cycle) {
600template <typename T, bool stable_sort = false,
601 typename Hash = typename absl::flat_hash_map<T, int>::hasher,
603 typename absl::flat_hash_map<T, int, Hash>::key_equal>
607namespace util {
610 int num_nodes, const std::vector<std::pair<int, int>>& arcs) {
611 return ::util::DenseIntTopologicalSortOrDie(num_nodes, arcs);
614 int num_nodes, const std::vector<std::pair<int, int>>& arcs) {
615 return ::util::DenseIntStableTopologicalSortOrDie(num_nodes, arcs);
619 const std::vector<T>& nodes, const std::vector<std::pair<T, T>>& arcs) {
620 return ::util::StableTopologicalSortOrDie<T>(nodes, arcs);
623template <class AdjacencyLists>
624absl::StatusOr<std::vector<typename GraphTraits<AdjacencyLists>::NodeIndex>>
627 if (adj.size() > std::numeric_limits<NodeIndex>::max()) {
628 return absl::InvalidArgumentError(
629 absl::StrFormat("Too many nodes: adj.size()=%v", adj.size()));
631 const NodeIndex num_nodes(adj.size());
632 std::vector<NodeIndex> indegree(static_cast<size_t>(num_nodes), NodeIndex(0));
633 std::vector<NodeIndex> topo_order;
634 topo_order.reserve(static_cast<size_t>(num_nodes));
635 for (NodeIndex from(0); from < num_nodes; ++from) {
636 for (const NodeIndex head : adj[from]) {
637 if (!(NodeIndex(0) <= head && head < num_nodes)) {
638 return absl::InvalidArgumentError(
639 absl::StrFormat("Invalid arc in adj[%v]: %v (num_nodes=%v)", from,
645 ++indegree[static_cast<size_t>(head)];
648 for (NodeIndex i(0); i < num_nodes; ++i) {
649 if (!indegree[static_cast<size_t>(i)]) topo_order.push_back(i);
652 while (num_visited < topo_order.size()) {
653 const NodeIndex from = topo_order[num_visited++];
654 for (const NodeIndex head : adj[from]) {
655 if (!--indegree[static_cast<size_t>(head)]) topo_order.push_back(head);
658 if (topo_order.size() < static_cast<size_t>(num_nodes)) {
659 return absl::InvalidArgumentError("The graph has a cycle");
664template <class AdjacencyLists>
666 std::vector<typename util::GraphTraits<AdjacencyLists>::NodeIndex>>
669 if (adj.size() > std::numeric_limits<NodeIndex>::max()) {
670 return absl::InvalidArgumentError(
671 absl::StrFormat("Too many nodes: adj.size()=%v", adj.size()));
673 const NodeIndex num_nodes(adj.size());
676 for (NodeIndex node(0); node < NodeIndex(node); ++node) {
677 for (const NodeIndex head : adj[node]) {
679 return absl::InvalidArgumentError(
680 absl::StrFormat("Invalid child %v in adj[%v]", head, node));
689 std::vector<bool> no_cycle_reachable_from(static_cast<size_t>(num_nodes),
696 decltype(adj[NodeIndex(0)].begin()) children;
697 decltype(adj[NodeIndex(0)].end()) children_end;
699 explicit DfsState(NodeIndex _node,
700 const decltype(adj[NodeIndex(0)])& neighbours)
702 children(neighbours.begin()),
703 children_end(neighbours.end()) {}
705 std::vector<DfsState> dfs_stack;
706 std::vector<bool> visited(static_cast<size_t>(num_nodes), false);
707 for (NodeIndex start_node(0); start_node < NodeIndex(num_nodes);
709 if (no_cycle_reachable_from[static_cast<size_t>(start_node)]) continue;
712 visited[static_cast<size_t>(start_node)] = true;
713 dfs_stack.push_back(DfsState(start_node, adj[start_node]));
714 while (!dfs_stack.empty()) {
715 DfsState* const cur_state = &dfs_stack.back();
717 cur_state->children != cur_state->children_end &&
718 no_cycle_reachable_from[static_cast<size_t>(*cur_state->children)]) {
721 if (cur_state->children == cur_state->children_end) {
722 no_cycle_reachable_from[static_cast<size_t>(cur_state->node)] = true;
727 const NodeIndex child = *cur_state->children;
736 if (no_cycle_reachable_from[static_cast<size_t>(child)]) continue;
737 if (visited[static_cast<size_t>(child)]) {
740 size_t cycle_start = dfs_stack.size() - 1;
741 while (dfs_stack[cycle_start].node != child) --cycle_start;
742 const size_t cycle_size = dfs_stack.size() - cycle_start;
743 std::vector<NodeIndex> cycle(cycle_size);
744 for (size_t c = 0; c < cycle_size; ++c) {
745 cycle[c] = dfs_stack[cycle_start + c].node;
751 dfs_stack.push_back(DfsState(child, adj[child]));
752 visited[static_cast<size_t>(child)] = true;
static StaticGraph FromArcs(NodeIndexType num_nodes, const ArcContainer &arcs)
void AddEdges(const std::vector< std::pair< T, T > > &edges)
Definition topologicalsorter.h:351
TopologicalSorter & operator=(const TopologicalSorter &)=delete
TopologicalSorter()=default
~TopologicalSorter()=default
void StartTraversal()
Definition topologicalsorter.h:414
int GetCurrentFringeSize()
Definition topologicalsorter.h:405
bool TraversalStarted() const
Definition topologicalsorter.h:428
void AddNode(const T &node)
Definition topologicalsorter.h:348
TopologicalSorter(const TopologicalSorter &)=delete
bool GetNext(T *node, bool *cyclic_ptr, std::vector< T > *output_cycle_nodes=nullptr)
Definition topologicalsorter.h:384
void AddEdge(const T &from, const T &to)
Definition topologicalsorter.h:359
DenseIntTopologicalSorterTpl(int num_nodes)
Definition topologicalsorter.h:213
static int RemoveDuplicates(std::vector< AdjacencyList > *lists, int skip_lists_smaller_than)
void AddNode(int node_index)
void AddEdge(int from, int to)
int GetCurrentFringeSize()
Definition topologicalsorter.h:246
void AddEdges(absl::Span< const std::pair< int, int > > edges)
bool TraversalStarted() const
Definition topologicalsorter.h:253
DenseIntTopologicalSorterTpl & operator=(const DenseIntTopologicalSorterTpl &)=delete
bool GetNext(int *next_node_index, bool *cyclic, std::vector< int > *output_cycle_nodes=nullptr)
DenseIntTopologicalSorterTpl(const DenseIntTopologicalSorterTpl &)=delete
absl::InlinedVector< int, 4 > AdjacencyList
Definition topologicalsorter.h:201
void ExtractCycle(std::vector< int > *cycle_nodes) const
DenseIntTopologicalSorterTpl()
Definition topologicalsorter.h:205
auto LogContainer(const ContainerT &container, const PolicyT &policy) -> decltype(gtl::LogRange(container.begin(), container.end(), policy))
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)
void STLClearHashIfBig(T *obj, size_t limit)
absl::StatusOr< std::vector< typename util::GraphTraits< AdjacencyLists >::NodeIndex > > FastTopologicalSort(const AdjacencyLists &adj)
Definition topologicalsorter.h:625
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
Definition topologicalsorter.h:613
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs)
Definition topologicalsorter.h:618
std::vector< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
Definition topologicalsorter.h:609
absl::StatusOr< std::vector< typename util::GraphTraits< AdjacencyLists >::NodeIndex > > FindCycleInGraph(const AdjacencyLists &adj)
Definition topologicalsorter.h:667
std::vector< T > TopologicalSortOrDieImpl(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs)
Definition topologicalsorter.h:512
ABSL_MUST_USE_RESULT bool DenseIntTopologicalSortImpl(int num_nodes, const std::vector< std::pair< int, int > > &arcs, std::vector< int > *topological_order)
Definition topologicalsorter.h:472
std::vector< int > DenseIntTopologicalSortOrDieImpl(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
Definition topologicalsorter.h:505
ABSL_MUST_USE_RESULT bool TopologicalSortImpl(absl::Span< const T > nodes, const std::vector< std::pair< T, T > > &arcs, std::vector< T > *topological_order, std::vector< T > *cycle)
Definition topologicalsorter.h:482
std::vector< T > RunTopologicalSorterOrDie(Sorter *sorter, int num_nodes, const std::vector< std::pair< T, T > > &arcs)
Definition topologicalsorter.h:495
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< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
Definition topologicalsorter.h:570
::util::internal::DenseIntTopologicalSorterTpl< false > DenseIntTopologicalSorter
Definition topologicalsorter.h:305
ABSL_MUST_USE_RESULT bool DenseIntStableTopologicalSort(int num_nodes, const std::vector< std::pair< int, int > > &arcs, std::vector< int > *topological_order)
Definition topologicalsorter.h:530
ABSL_MUST_USE_RESULT bool TopologicalSort(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs, std::vector< T > *topological_order)
Definition topologicalsorter.h:538
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
Definition topologicalsorter.h:575
ABSL_MUST_USE_RESULT bool StableTopologicalSort(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs, std::vector< T > *topological_order)
Definition topologicalsorter.h:554
std::vector< T > TopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs)
Definition topologicalsorter.h:581
::util::internal::DenseIntTopologicalSorterTpl< true > DenseIntStableTopologicalSorter
Definition topologicalsorter.h:296
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs)
Definition topologicalsorter.h:587
ABSL_MUST_USE_RESULT bool DenseIntTopologicalSort(int num_nodes, const std::vector< std::pair< int, int > > &arcs, std::vector< int > *topological_order)
Definition topologicalsorter.h:523
ABSL_MUST_USE_RESULT std::vector< int > FindCycleInDenseIntGraph(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
Definition topologicalsorter.h:153
trees with all degrees equal to
std::decay_t< decltype(*(std::declval< NeighborRangeType >().begin()))> NodeIndex
::util::DenseIntStableTopologicalSorter DenseIntStableTopologicalSorter
Definition topologicalsorter.h:598
::util::DenseIntTopologicalSorter DenseIntTopologicalSorter
Definition topologicalsorter.h:599