30#ifndef UTIL_GRAPH_TOPOLOGICALSORTER_H__
31#define UTIL_GRAPH_TOPOLOGICALSORTER_H__
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"
46#include "absl/types/span.h"
86template <
class AdjacencyLists>
95template <
class AdjacencyLists>
113 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
118 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
123 const std::vector<std::pair<T, T>>& arcs);
130 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
135 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs,
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,
163 int num_nodes,
const std::vector<std::pair<int, int>>& arcs);
165 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
168 int num_nodes,
const std::vector<std::pair<int, int>>& arcs);
172template <
typename T,
typename Sorter>
174 Sorter* sorter,
const std::vector<std::pair<T, T>>& arcs,
175 std::vector<T>* topological_order_or_cycle);
189template <
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) {}
224 void AddEdges(absl::Span<
const std::pair<int, int>> edges);
235 bool GetNext(
int* next_node_index,
bool* cyclic,
236 std::vector<int>* output_cycle_nodes =
nullptr);
240 return nodes_with_zero_indegree_.size();
253 int skip_lists_smaller_than);
260 std::vector<AdjacencyList> adjacency_lists_;
262 bool traversal_started_;
266 typename std::conditional<
269 std::priority_queue<int, std::vector<int>, std::greater<int>>,
270 std::queue<int>>::type nodes_with_zero_indegree_;
271 std::vector<int> indegree_;
276 int num_edges_added_since_last_duplicate_removal_;
279extern template class DenseIntTopologicalSorterTpl<false>;
280extern template class DenseIntTopologicalSorterTpl<true>;
321template <
typename T,
bool stable_sort =
false,
322 typename Hash =
typename absl::flat_hash_map<T, int>::hasher,
324 typename absl::flat_hash_map<T, int, Hash>::key_equal>
345 void AddEdges(
const std::vector<std::pair<T, T>>& edges) {
346 for (
const auto& [from,
to] : edges)
AddEdge(from,
to);
356 const int from_int = LookupOrInsertNode(from);
357 const int to_int = LookupOrInsertNode(
to);
358 int_sorter_.
AddEdge(from_int, to_int);
379 std::vector<T>* output_cycle_nodes =
nullptr) {
383 &node_index, cyclic_ptr,
384 output_cycle_nodes ? &cycle_int_nodes_ :
nullptr)) {
385 if (*cyclic_ptr && output_cycle_nodes !=
nullptr) {
386 output_cycle_nodes->clear();
387 for (
const int int_node : cycle_int_nodes_) {
388 output_cycle_nodes->push_back(nodes_[int_node]);
393 *node = nodes_[node_index];
410 nodes_.resize(node_to_index_.size());
413 for (
auto& node_and_index : node_to_index_) {
414 nodes_[node_and_index.second] = std::move(node_and_index.first);
428 absl::flat_hash_map<T, int, Hash, KeyEqual> node_to_index_;
431 std::vector<T> nodes_;
438 std::vector<int> cycle_int_nodes_;
442 int LookupOrInsertNode(
const T& node) {
450template <
typename T,
typename Sorter>
452 Sorter* sorter,
const std::vector<std::pair<T, T>>& arcs,
455 sorter->AddEdges(arcs);
457 sorter->StartTraversal();
459 while (sorter->GetNext(&
next, &cyclic, cycle)) {
465template <
bool stable_sort = false>
467 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
475template <
typename T,
bool stable_sort = false>
477 absl::Span<const T>
nodes,
const std::vector<std::pair<T, T>>& arcs,
480 for (
const T& node :
nodes) {
488template <
typename T,
typename Sorter>
490 Sorter* sorter,
int num_nodes,
const std::vector<std::pair<T, T>>& arcs) {
491 std::vector<T> topo_order;
492 topo_order.reserve(num_nodes);
498template <
bool stable_sort = false>
500 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
505template <
typename T,
bool stable_sort = false>
507 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs) {
509 for (
const T& node :
nodes) {
518 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
525 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
533 const std::vector<std::pair<T, T>>& arcs,
541 const std::vector<std::pair<T, T>>& arcs,
549 const std::vector<std::pair<T, T>>& arcs,
557 const std::vector<std::pair<T, T>>& arcs,
559 std::vector<T>* cycle) {
565 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
570 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
576 const std::vector<std::pair<T, T>>& arcs) {
582 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs) {
594template <
typename T,
bool stable_sort =
false,
595 typename Hash =
typename absl::flat_hash_map<T, int>::hasher,
597 typename absl::flat_hash_map<T, int, Hash>::key_equal>
604 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
605 return ::util::DenseIntTopologicalSortOrDie(num_nodes, arcs);
608 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
609 return ::util::DenseIntStableTopologicalSortOrDie(num_nodes, arcs);
613 const std::vector<T>&
nodes,
const std::vector<std::pair<T, T>>& arcs) {
614 return ::util::StableTopologicalSortOrDie<T>(
nodes, arcs);
617template <
class AdjacencyLists>
619 const AdjacencyLists& adj) {
620 const size_t num_nodes = adj.size();
621 if (num_nodes > std::numeric_limits<int>::max()) {
622 return absl::InvalidArgumentError(
"More than kint32max nodes");
624 std::vector<int> indegree(num_nodes, 0);
625 std::vector<int> topo_order;
626 topo_order.reserve(num_nodes);
627 for (
int from = 0; from < num_nodes; ++from) {
628 for (
const int head : adj[from]) {
631 if (
static_cast<uint32_t
>(
head) >= num_nodes) {
632 return absl::InvalidArgumentError(
633 absl::StrFormat(
"Invalid arc in adj[%d]: %d (num_nodes=%d)", from,
642 for (
int i = 0; i < num_nodes; ++i) {
643 if (!indegree[i]) topo_order.push_back(i);
645 size_t num_visited = 0;
646 while (num_visited < topo_order.size()) {
647 const int from = topo_order[num_visited++];
648 for (
const int head : adj[from]) {
649 if (!--indegree[
head]) topo_order.push_back(
head);
652 if (topo_order.size() <
static_cast<size_t>(num_nodes)) {
653 return absl::InvalidArgumentError(
"The graph has a cycle");
658template <
class AdjacencyLists>
660 const size_t num_nodes = adj.size();
661 if (num_nodes > std::numeric_limits<int>::max()) {
662 return absl::InvalidArgumentError(
663 absl::StrFormat(
"Too many nodes: adj.size()=%d", adj.size()));
670 std::vector<bool> no_cycle_reachable_from(num_nodes,
false);
677 explicit DfsState(
int _node) : node(_node), adj_list_index(0) {}
679 std::vector<DfsState> dfs_stack;
680 std::vector<bool> in_cur_stack(num_nodes,
false);
681 for (
int start_node = 0; start_node < static_cast<int>(num_nodes);
683 if (no_cycle_reachable_from[start_node])
continue;
685 dfs_stack.push_back(DfsState(start_node));
686 in_cur_stack[start_node] =
true;
687 while (!dfs_stack.empty()) {
688 DfsState* cur_state = &dfs_stack.back();
689 if (
static_cast<size_t>(cur_state->adj_list_index) >=
690 adj[cur_state->node].size()) {
691 no_cycle_reachable_from[cur_state->node] =
true;
692 in_cur_stack[cur_state->node] =
false;
693 dfs_stack.pop_back();
700 const int child = adj[cur_state->node][cur_state->adj_list_index++];
701 if (
static_cast<size_t>(child) >= num_nodes) {
702 return absl::InvalidArgumentError(absl::StrFormat(
703 "Invalid child %d in adj[%d]", child, cur_state->node));
705 if (no_cycle_reachable_from[child])
continue;
706 if (in_cur_stack[child]) {
709 int cycle_start = dfs_stack.size() - 1;
710 while (dfs_stack[cycle_start].node != child) --cycle_start;
711 const int cycle_size = dfs_stack.size() - cycle_start;
712 std::vector<int> cycle(cycle_size);
713 for (
int c = 0; c < cycle_size; ++c) {
714 cycle[c] = dfs_stack[cycle_start + c].node;
719 dfs_stack.push_back(DfsState(child));
720 in_cur_stack[child] =
true;
722 if (adj[child].
size() > std::numeric_limits<int>::max()) {
723 return absl::InvalidArgumentError(absl::StrFormat(
724 "Invalid adj[%d].size() = %d", child, adj[child].
size()));
729 return std::vector<int>{};
void AddEdges(const std::vector< std::pair< T, T > > &edges)
Shortcut to AddEdge() in bulk. Not optimized.
TopologicalSorter & operator=(const TopologicalSorter &)=delete
int GetCurrentFringeSize()
bool TraversalStarted() const
void AddNode(const T &node)
TopologicalSorter(const TopologicalSorter &)=delete
This type is neither copyable nor movable.
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)
static
void AddNode(int node_index)
void AddEdge(int from, int to)
int GetCurrentFringeSize()
void AddEdges(absl::Span< const std::pair< int, int > > edges)
Performs AddEdge() in bulk. Much faster if you add all edges at once.
bool TraversalStarted() const
absl::InlinedVector< int, 4 > AdjacencyList
To store the adjacency lists efficiently.
DenseIntTopologicalSorterTpl & operator=(const DenseIntTopologicalSorterTpl &)=delete
bool GetNext(int *next_node_index, bool *cyclic, std::vector< int > *output_cycle_nodes=nullptr)
DenseIntTopologicalSorterTpl(const DenseIntTopologicalSorterTpl &)=delete
This type is neither copyable nor movable.
void ExtractCycle(std::vector< int > *cycle_nodes) const
To extract a cycle. When there is no cycle, cycle_nodes will be empty.
DenseIntTopologicalSorterTpl()
std::vector< NodeIndex > topological_order
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< int > > FastTopologicalSort(const AdjacencyLists &adj)
std::vector< int > DenseIntStableTopologicalSortOrDie(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
absl::StatusOr< std::vector< int > > FindCycleInGraph(const AdjacencyLists &adj)
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)
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)
Now, the OrDie() versions, which directly return the topological order.
ABSL_MUST_USE_RESULT bool RunTopologicalSorter(Sorter *sorter, const std::vector< std::pair< T, T > > &arcs, std::vector< T > *topological_order_or_cycle)
Internal wrapper around the *TopologicalSort classes.
A collections of i/o utilities for the Graph classes in ./graph.h.
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)
OrDie() variant of the above.
::util::internal::DenseIntTopologicalSorterTpl< true > DenseIntStableTopologicalSorter
std::vector< T > StableTopologicalSortOrDie(const std::vector< T > &nodes, const std::vector< std::pair< T, T > > &arcs)
OrDie() variant of the above.
ABSL_MUST_USE_RESULT bool DenseIntTopologicalSort(int num_nodes, const std::vector< std::pair< int, int > > &arcs, std::vector< int > *topological_order)
Implementations of the "simple API" functions declared at the top.
ABSL_MUST_USE_RESULT std::vector< int > FindCycleInDenseIntGraph(int num_nodes, const std::vector< std::pair< int, int > > &arcs)
______________________ END OF THE RECOMMENDED API ___________________________
trees with all degrees equal to
::util::DenseIntStableTopologicalSorter DenseIntStableTopologicalSorter
::util::DenseIntTopologicalSorter DenseIntTopologicalSorter