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"
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);
154 int num_nodes,
const std::vector<std::pair<int, int>>& 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>
206 : traversal_started_(false),
208 num_edges_added_since_last_duplicate_removal_(0) {}
214 : adjacency_lists_(num_nodes),
215 traversal_started_(false),
217 num_edges_added_since_last_duplicate_removal_(0) {}
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);
248 return nodes_with_zero_indegree_.size();
261 int skip_lists_smaller_than);
268 std::vector<AdjacencyList> adjacency_lists_;
270 bool traversal_started_;
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_;
284 int num_edges_added_since_last_duplicate_removal_;
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) {
352 for (
const auto& [from,
to] : edges)
AddEdge(from,
to);
362 const int from_int = LookupOrInsertNode(from);
363 const int to_int = LookupOrInsertNode(
to);
364 int_sorter_.AddEdge(from_int, to_int);
385 std::vector<T>* output_cycle_nodes =
nullptr) {
388 if (!int_sorter_.GetNext(
389 &node_index, cyclic_ptr,
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]);
399 *node = nodes_[node_index];
407 return int_sorter_.GetCurrentFringeSize();
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);
423 int_sorter_.StartTraversal();
434 absl::flat_hash_map<T, int, Hash, KeyEqual> node_to_index_;
437 std::vector<T> nodes_;
444 std::vector<int> cycle_int_nodes_;
448 int LookupOrInsertNode(
const T& node) {
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();
461 sorter->AddEdges(arcs);
463 sorter->StartTraversal();
465 while (sorter->GetNext(&next, &cyclic, cycle)) {
466 topological_order->push_back(next);
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);
478 &sorter, arcs, topological_order,
nullptr);
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) {
490 topological_order, cycle);
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;
498 topo_order.reserve(num_nodes);
504template <
bool stable_sort = false>
506 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
511template <
typename T,
bool stable_sort = false>
513 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs) {
515 for (
const T& node : nodes) {
524 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
525 std::vector<int>* topological_order) {
531 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
532 std::vector<int>* topological_order) {
539 const std::vector<std::pair<T, T>>& arcs,
540 std::vector<T>* topological_order) {
547 const std::vector<std::pair<T, T>>& arcs,
548 std::vector<T>* topological_order, std::vector<T>* cycle) {
555 const std::vector<std::pair<T, T>>& arcs,
556 std::vector<T>* topological_order) {
563 const std::vector<std::pair<T, T>>& arcs,
564 std::vector<T>* topological_order,
565 std::vector<T>* cycle) {
571 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
576 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
582 const std::vector<std::pair<T, T>>& arcs) {
588 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs) {
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>
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);
651 size_t num_visited = 0;
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]) {
678 if (head >= num_nodes) {
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)]) {
719 ++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;
723 dfs_stack.pop_back();
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;
757 return std::vector<NodeIndex>{};
static StaticGraph FromArcs(NodeIndexType num_nodes, const ArcContainer &arcs)
void AddEdges(const std::vector< std::pair< T, T > > &edges)
TopologicalSorter & operator=(const TopologicalSorter &)=delete
TopologicalSorter()=default
~TopologicalSorter()=default
int GetCurrentFringeSize()
bool TraversalStarted() const
void AddNode(const T &node)
TopologicalSorter(const TopologicalSorter &)=delete
bool GetNext(T *node, bool *cyclic_ptr, std::vector< T > *output_cycle_nodes=nullptr)
void AddEdge(const T &from, const T &to)
DenseIntTopologicalSorterTpl(int num_nodes)
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()
void AddEdges(absl::Span< const std::pair< int, int > > edges)
bool TraversalStarted() const
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
void ExtractCycle(std::vector< int > *cycle_nodes) const
DenseIntTopologicalSorterTpl()
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)
std::vector< int > DenseIntStableTopologicalSortOrDie(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)
std::vector< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
absl::StatusOr< std::vector< typename util::GraphTraits< AdjacencyLists >::NodeIndex > > FindCycleInGraph(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 DenseIntTopologicalSortImpl(int num_nodes, const std::vector< std::pair< int, int > > &arcs, std::vector< int > *topological_order)
std::vector< int > DenseIntTopologicalSortOrDieImpl(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
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)
std::vector< T > RunTopologicalSorterOrDie(Sorter *sorter, int num_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)
std::vector< int > DenseIntTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
::util::internal::DenseIntTopologicalSorterTpl< false > DenseIntTopologicalSorter
ABSL_MUST_USE_RESULT bool DenseIntStableTopologicalSort(int num_nodes, const std::vector< std::pair< int, int > > &arcs, std::vector< int > *topological_order)
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 > 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< true > DenseIntStableTopologicalSorter
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs)
ABSL_MUST_USE_RESULT bool DenseIntTopologicalSort(int num_nodes, const std::vector< std::pair< int, int > > &arcs, std::vector< int > *topological_order)
ABSL_MUST_USE_RESULT std::vector< int > FindCycleInDenseIntGraph(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
trees with all degrees equal to
std::decay_t< decltype(*(std::declval< NeighborRangeType >().begin()))> NodeIndex
::util::DenseIntStableTopologicalSorter DenseIntStableTopologicalSorter
::util::DenseIntTopologicalSorter DenseIntTopologicalSorter