30 #ifndef UTIL_GRAPH_TOPOLOGICALSORTER_H__
31 #define UTIL_GRAPH_TOPOLOGICALSORTER_H__
36 #include <type_traits>
40 #include "absl/base/attributes.h"
41 #include "absl/container/flat_hash_map.h"
42 #include "absl/container/inlined_vector.h"
43 #include "absl/status/status.h"
44 #include "absl/status/statusor.h"
45 #include "absl/strings/str_format.h"
86 template <
class AdjacencyLists>
95 template <
class AdjacencyLists>
96 absl::StatusOr<std::vector<int>>
FindCycleInGraph(
const AdjacencyLists& adj);
111 template <
typename T>
113 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
114 std::vector<T>* topological_order);
116 template <
typename T>
118 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
119 std::vector<T>* topological_order, std::vector<T>* cycle);
121 template <
typename T>
123 const std::vector<std::pair<T, T>>& arcs);
128 template <
typename T>
130 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
131 std::vector<T>* topological_order);
133 template <
typename T>
135 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
136 std::vector<T>* topological_order, std::vector<T>* cycle);
138 template <
typename T>
140 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs);
146 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
160 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
161 std::vector<int>* topological_order);
163 int num_nodes,
const std::vector<std::pair<int, int>>& arcs);
165 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
166 std::vector<int>* topological_order);
168 int num_nodes,
const std::vector<std::pair<int, int>>& arcs);
172 template <
typename T,
typename Sorter>
174 Sorter* sorter,
const std::vector<std::pair<T, T>>& arcs,
175 std::vector<T>* topological_order_or_cycle);
189 template <
bool stable_sort = false>
198 : traversal_started_(false),
200 num_edges_added_since_last_duplicate_removal_(0) {}
206 : adjacency_lists_(num_nodes),
207 traversal_started_(false),
209 num_edges_added_since_last_duplicate_removal_(0) {}
219 void AddEdges(
const std::vector<std::pair<int, int>>& edges);
225 void AddEdge(
int from,
int to);
230 bool GetNext(
int* next_node_index,
bool* cyclic,
231 std::vector<int>* output_cycle_nodes =
nullptr);
235 return nodes_with_zero_indegree_.size();
248 int skip_lists_smaller_than);
255 std::vector<AdjacencyList> adjacency_lists_;
257 bool traversal_started_;
261 typename std::conditional<
264 std::priority_queue<int, std::vector<int>, std::greater<int>>,
265 std::queue<int>>::type nodes_with_zero_indegree_;
266 std::vector<int> indegree_;
271 int num_edges_added_since_last_duplicate_removal_;
277 extern template class DenseIntTopologicalSorterTpl<false>;
278 extern template class DenseIntTopologicalSorterTpl<true>;
284 typedef ::util::internal::DenseIntTopologicalSorterTpl<
293 typedef ::util::internal::DenseIntTopologicalSorterTpl<
319 template <
typename T,
bool stable_sort =
false,
320 typename Hash =
typename absl::flat_hash_map<T, int>::hasher,
322 typename absl::flat_hash_map<T, int, Hash>::key_equal>
336 void AddNode(
const T& node) { int_sorter_.AddNode(LookupOrInsertNode(node)); }
339 void AddEdges(
const std::vector<std::pair<T, T>>& edges) {
340 for (
const auto& [from, to] : edges)
AddEdge(from, to);
350 const int from_int = LookupOrInsertNode(from);
351 const int to_int = LookupOrInsertNode(to);
352 int_sorter_.AddEdge(from_int, to_int);
373 std::vector<T>* output_cycle_nodes =
nullptr) {
376 if (!int_sorter_.GetNext(
377 &node_index, cyclic_ptr,
378 output_cycle_nodes ? &cycle_int_nodes_ :
nullptr)) {
379 if (*cyclic_ptr && output_cycle_nodes !=
nullptr) {
380 output_cycle_nodes->clear();
381 for (
const int int_node : cycle_int_nodes_) {
382 output_cycle_nodes->push_back(nodes_[int_node]);
387 *node = nodes_[node_index];
395 return int_sorter_.GetCurrentFringeSize();
404 nodes_.resize(node_to_index_.size());
407 for (
auto& node_and_index : node_to_index_) {
408 nodes_[node_and_index.second] = std::move(node_and_index.first);
411 int_sorter_.StartTraversal();
422 absl::flat_hash_map<T, int, Hash, KeyEqual> node_to_index_;
425 std::vector<T> nodes_;
432 std::vector<int> cycle_int_nodes_;
436 int LookupOrInsertNode(
const T& node) {
446 template <
typename T,
typename Sorter>
448 Sorter* sorter,
const std::vector<std::pair<T, T>>& arcs,
449 std::vector<T>* topological_order, std::vector<T>* cycle) {
450 topological_order->clear();
451 sorter->AddEdges(arcs);
453 sorter->StartTraversal();
455 while (sorter->GetNext(&
next, &cyclic, cycle)) {
456 topological_order->push_back(
next);
461 template <
bool stable_sort = false>
463 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
464 std::vector<int>* topological_order) {
466 topological_order->reserve(num_nodes);
467 return RunTopologicalSorter<int, decltype(sorter)>(
468 &sorter, arcs, topological_order,
nullptr);
471 template <
typename T,
bool stable_sort = false>
473 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
474 std::vector<T>* topological_order, std::vector<T>* cycle) {
476 for (
const T& node :
nodes) {
479 return RunTopologicalSorter<T, decltype(sorter)>(&sorter, arcs,
480 topological_order, cycle);
484 template <
typename T,
typename Sorter>
486 Sorter* sorter,
int num_nodes,
const std::vector<std::pair<T, T>>& arcs) {
487 std::vector<T> topo_order;
488 topo_order.reserve(num_nodes);
494 template <
bool stable_sort = false>
496 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
501 template <
typename T,
bool stable_sort = false>
503 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs) {
505 for (
const T& node :
nodes) {
514 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
515 std::vector<int>* topological_order) {
516 return internal::DenseIntTopologicalSortImpl<false>(num_nodes, arcs,
521 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
522 std::vector<int>* topological_order) {
523 return internal::DenseIntTopologicalSortImpl<true>(num_nodes, arcs,
527 template <
typename T>
529 const std::vector<std::pair<T, T>>& arcs,
530 std::vector<T>* topological_order) {
531 return internal::TopologicalSortImpl<T, false>(
nodes, arcs, topological_order,
535 template <
typename T>
537 const std::vector<std::pair<T, T>>& arcs,
538 std::vector<T>* topological_order, std::vector<T>* cycle) {
539 return internal::TopologicalSortImpl<T, false>(
nodes, arcs, topological_order,
543 template <
typename T>
545 const std::vector<std::pair<T, T>>& arcs,
546 std::vector<T>* topological_order) {
547 return internal::TopologicalSortImpl<T, true>(
nodes, arcs, topological_order,
551 template <
typename T>
553 const std::vector<std::pair<T, T>>& arcs,
554 std::vector<T>* topological_order,
555 std::vector<T>* cycle) {
556 return internal::TopologicalSortImpl<T, true>(
nodes, arcs, topological_order,
561 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
562 return internal::DenseIntTopologicalSortOrDieImpl<false>(num_nodes, arcs);
566 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
567 return internal::DenseIntTopologicalSortOrDieImpl<true>(num_nodes, arcs);
570 template <
typename T>
572 const std::vector<std::pair<T, T>>& arcs) {
573 return internal::TopologicalSortOrDieImpl<T, false>(
nodes, arcs);
576 template <
typename T>
578 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs) {
579 return internal::TopologicalSortOrDieImpl<T, true>(
nodes, arcs);
590 template <
typename T,
bool stable_sort =
false,
591 typename Hash =
typename absl::flat_hash_map<T, int>::hasher,
593 typename absl::flat_hash_map<T, int, Hash>::key_equal>
600 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
604 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
607 template <
typename T>
609 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs) {
610 return ::util::StableTopologicalSortOrDie<T>(
nodes, arcs);
613 template <
class AdjacencyLists>
615 const AdjacencyLists& adj) {
616 const size_t num_nodes = adj.size();
618 return absl::InvalidArgumentError(
"More than kint32max nodes");
620 std::vector<int> indegree(num_nodes, 0);
621 std::vector<int> topo_order;
622 topo_order.reserve(num_nodes);
623 for (
int from = 0; from < num_nodes; ++from) {
624 for (
const int head : adj[from]) {
627 if (
static_cast<uint32_t
>(
head) >= num_nodes) {
628 return absl::InvalidArgumentError(
629 absl::StrFormat(
"Invalid arc in adj[%d]: %d (num_nodes=%d)", from,
638 for (
int i = 0; i < num_nodes; ++i) {
639 if (!indegree[i]) topo_order.push_back(i);
641 size_t num_visited = 0;
642 while (num_visited < topo_order.size()) {
643 const int from = topo_order[num_visited++];
644 for (
const int head : adj[from]) {
645 if (!--indegree[
head]) topo_order.push_back(
head);
648 if (topo_order.size() <
static_cast<size_t>(num_nodes)) {
649 return absl::InvalidArgumentError(
"The graph has a cycle");
654 template <
class AdjacencyLists>
656 const size_t num_nodes = adj.size();
658 return absl::InvalidArgumentError(
659 absl::StrFormat(
"Too many nodes: adj.size()=%d", adj.size()));
666 std::vector<bool> no_cycle_reachable_from(num_nodes,
false);
673 explicit DfsState(
int _node) : node(_node), adj_list_index(0) {}
675 std::vector<DfsState> dfs_stack;
676 std::vector<bool> in_cur_stack(num_nodes,
false);
677 for (
int start_node = 0; start_node < static_cast<int>(num_nodes);
679 if (no_cycle_reachable_from[start_node])
continue;
681 dfs_stack.push_back(DfsState(start_node));
682 in_cur_stack[start_node] =
true;
683 while (!dfs_stack.empty()) {
684 DfsState* cur_state = &dfs_stack.back();
685 if (
static_cast<size_t>(cur_state->adj_list_index) >=
686 adj[cur_state->node].size()) {
687 no_cycle_reachable_from[cur_state->node] =
true;
688 in_cur_stack[cur_state->node] =
false;
689 dfs_stack.pop_back();
696 const int child = adj[cur_state->node][cur_state->adj_list_index++];
697 if (
static_cast<size_t>(child) >= num_nodes) {
698 return absl::InvalidArgumentError(absl::StrFormat(
699 "Invalid child %d in adj[%d]", child, cur_state->node));
701 if (no_cycle_reachable_from[child])
continue;
702 if (in_cur_stack[child]) {
705 int cycle_start = dfs_stack.size() - 1;
706 while (dfs_stack[cycle_start].node != child) --cycle_start;
707 const int cycle_size = dfs_stack.size() - cycle_start;
708 std::vector<int> cycle(cycle_size);
709 for (
int c = 0; c < cycle_size; ++c) {
710 cycle[c] = dfs_stack[cycle_start + c].node;
715 dfs_stack.push_back(DfsState(child));
716 in_cur_stack[child] =
true;
719 return absl::InvalidArgumentError(absl::StrFormat(
720 "Invalid adj[%d].size() = %d", child, adj[child].size()));
725 return std::vector<int>{};
void AddEdge(const T &from, const T &to)
void AddEdges(const std::vector< std::pair< T, T >> &edges)
bool GetNext(T *node, bool *cyclic_ptr, std::vector< T > *output_cycle_nodes=nullptr)
int GetCurrentFringeSize()
bool TraversalStarted() const
void AddNode(const T &node)
void ExtractCycle(std::vector< int > *cycle_nodes) const
void AddEdge(int from, int to)
void AddNode(int node_index)
DenseIntTopologicalSorterTpl(int num_nodes)
absl::InlinedVector< int, 4 > AdjacencyList
static int RemoveDuplicates(std::vector< AdjacencyList > *lists, int skip_lists_smaller_than)
DenseIntTopologicalSorterTpl()
int GetCurrentFringeSize()
bool TraversalStarted() const
void AddEdges(const std::vector< std::pair< int, int >> &edges)
bool GetNext(int *next_node_index, bool *cyclic, std::vector< int > *output_cycle_nodes=nullptr)
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)
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
absl::StatusOr< std::vector< int > > FindCycleInGraph(const AdjacencyLists &adj)
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
std::vector< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
absl::StatusOr< std::vector< int > > FastTopologicalSort(const AdjacencyLists &adj)
std::vector< T > TopologicalSortOrDieImpl(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
ABSL_MUST_USE_RESULT bool RunTopologicalSorter(Sorter *sorter, const std::vector< std::pair< T, T >> &arcs, std::vector< T > *topological_order_or_cycle)
ABSL_MUST_USE_RESULT bool TopologicalSortImpl(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs, std::vector< T > *topological_order, std::vector< T > *cycle)
std::vector< T > RunTopologicalSorterOrDie(Sorter *sorter, int num_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 DenseIntTopologicalSortImpl(int num_nodes, const std::vector< std::pair< int, int >> &arcs, std::vector< int > *topological_order)
uint64_t Hash(uint64_t num, uint64_t c)
ABSL_MUST_USE_RESULT bool DenseIntStableTopologicalSort(int num_nodes, const std::vector< std::pair< int, int >> &arcs, std::vector< int > *topological_order)
::util::internal::DenseIntTopologicalSorterTpl< true > DenseIntStableTopologicalSorter
ABSL_MUST_USE_RESULT std::vector< int > FindCycleInDenseIntGraph(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
ABSL_MUST_USE_RESULT bool DenseIntTopologicalSort(int num_nodes, const std::vector< std::pair< int, int >> &arcs, std::vector< int > *topological_order)
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
ABSL_MUST_USE_RESULT bool StableTopologicalSort(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs, std::vector< T > *topological_order)
std::vector< T > TopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
::util::internal::DenseIntTopologicalSorterTpl< false > DenseIntTopologicalSorter
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< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int >> &arcs)
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T >> &arcs)
::util::DenseIntStableTopologicalSorter DenseIntStableTopologicalSorter
::util::DenseIntTopologicalSorter DenseIntTopologicalSorter