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"
87template <
class AdjacencyLists>
89 std::vector<typename util::GraphTraits<AdjacencyLists>::NodeIndex>>
98template <
class AdjacencyLists>
100 std::vector<typename util::GraphTraits<AdjacencyLists>::NodeIndex>>
118 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs,
119 std::vector<T>* topological_order);
123 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs,
124 std::vector<T>* topological_order, std::vector<T>* cycle);
128 const std::vector<std::pair<T, T>>& arcs);
135 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs,
136 std::vector<T>* topological_order);
140 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs,
141 std::vector<T>* topological_order, std::vector<T>* cycle);
145 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs);
151 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);
170 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
171 std::vector<int>* topological_order);
173 int num_nodes,
const std::vector<std::pair<int, int>>& arcs);
177template <
typename T,
typename Sorter>
179 Sorter* sorter,
const std::vector<std::pair<T, T>>& arcs,
180 std::vector<T>* topological_order_or_cycle);
194template <
bool stable_sort = false>
203 : traversal_started_(false),
205 num_edges_added_since_last_duplicate_removal_(0) {}
211 : adjacency_lists_(num_nodes),
212 traversal_started_(false),
214 num_edges_added_since_last_duplicate_removal_(0) {}
229 void AddEdges(absl::Span<
const std::pair<int, int>> edges);
240 bool GetNext(
int* next_node_index,
bool* cyclic,
241 std::vector<int>* output_cycle_nodes =
nullptr);
245 return nodes_with_zero_indegree_.size();
258 int skip_lists_smaller_than);
265 std::vector<AdjacencyList> adjacency_lists_;
267 bool traversal_started_;
271 typename std::conditional<
274 std::priority_queue<int, std::vector<int>, std::greater<int>>,
275 std::queue<int>>::type nodes_with_zero_indegree_;
276 std::vector<int> indegree_;
281 int num_edges_added_since_last_duplicate_removal_;
324template <
typename T,
bool stable_sort =
false,
325 typename Hash =
typename absl::flat_hash_map<T, int>::hasher,
327 typename absl::flat_hash_map<T, int, Hash>::key_equal>
345 void AddNode(
const T& node) { int_sorter_.AddNode(LookupOrInsertNode(node)); }
348 void AddEdges(
const std::vector<std::pair<T, T>>& edges) {
349 for (
const auto& [from,
to] : edges)
AddEdge(from,
to);
359 const int from_int = LookupOrInsertNode(from);
360 const int to_int = LookupOrInsertNode(
to);
361 int_sorter_.AddEdge(from_int, to_int);
382 std::vector<T>* output_cycle_nodes =
nullptr) {
385 if (!int_sorter_.GetNext(
386 &node_index, cyclic_ptr,
387 output_cycle_nodes ? &cycle_int_nodes_ :
nullptr)) {
388 if (*cyclic_ptr && output_cycle_nodes !=
nullptr) {
389 output_cycle_nodes->clear();
390 for (
const int int_node : cycle_int_nodes_) {
391 output_cycle_nodes->push_back(nodes_[int_node]);
396 *node = nodes_[node_index];
404 return int_sorter_.GetCurrentFringeSize();
413 nodes_.resize(node_to_index_.size());
416 for (
auto& node_and_index : node_to_index_) {
417 nodes_[node_and_index.second] = std::move(node_and_index.first);
420 int_sorter_.StartTraversal();
431 absl::flat_hash_map<T, int, Hash, KeyEqual> node_to_index_;
434 std::vector<T> nodes_;
441 std::vector<int> cycle_int_nodes_;
445 int LookupOrInsertNode(
const T& node) {
453template <
typename T,
typename Sorter>
455 Sorter* sorter,
const std::vector<std::pair<T, T>>& arcs,
456 std::vector<T>* topological_order, std::vector<T>* cycle) {
457 topological_order->clear();
458 sorter->AddEdges(arcs);
460 sorter->StartTraversal();
462 while (sorter->GetNext(&next, &cyclic, cycle)) {
463 topological_order->push_back(next);
468template <
bool stable_sort = false>
470 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
471 std::vector<int>* topological_order) {
473 topological_order->reserve(num_nodes);
475 &sorter, arcs, topological_order,
nullptr);
478template <
typename T,
bool stable_sort = false>
480 absl::Span<const T> nodes,
const std::vector<std::pair<T, T>>& arcs,
481 std::vector<T>* topological_order, std::vector<T>* cycle) {
483 for (
const T& node : nodes) {
487 topological_order, cycle);
491template <
typename T,
typename Sorter>
493 Sorter* sorter,
int num_nodes,
const std::vector<std::pair<T, T>>& arcs) {
494 std::vector<T> topo_order;
495 topo_order.reserve(num_nodes);
501template <
bool stable_sort = false>
503 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
508template <
typename T,
bool stable_sort = false>
510 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs) {
512 for (
const T& node : nodes) {
521 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
522 std::vector<int>* topological_order) {
528 int num_nodes,
const std::vector<std::pair<int, int>>& arcs,
529 std::vector<int>* topological_order) {
536 const std::vector<std::pair<T, T>>& arcs,
537 std::vector<T>* topological_order) {
544 const std::vector<std::pair<T, T>>& arcs,
545 std::vector<T>* topological_order, std::vector<T>* cycle) {
552 const std::vector<std::pair<T, T>>& arcs,
553 std::vector<T>* topological_order) {
560 const std::vector<std::pair<T, T>>& arcs,
561 std::vector<T>* topological_order,
562 std::vector<T>* cycle) {
568 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
573 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
579 const std::vector<std::pair<T, T>>& arcs) {
585 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs) {
597template <
typename T,
bool stable_sort =
false,
598 typename Hash =
typename absl::flat_hash_map<T, int>::hasher,
600 typename absl::flat_hash_map<T, int, Hash>::key_equal>
607 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
608 return ::util::DenseIntTopologicalSortOrDie(num_nodes, arcs);
611 int num_nodes,
const std::vector<std::pair<int, int>>& arcs) {
612 return ::util::DenseIntStableTopologicalSortOrDie(num_nodes, arcs);
616 const std::vector<T>& nodes,
const std::vector<std::pair<T, T>>& arcs) {
617 return ::util::StableTopologicalSortOrDie<T>(nodes, arcs);
620template <
class AdjacencyLists>
621absl::StatusOr<std::vector<typename GraphTraits<AdjacencyLists>::NodeIndex>>
624 if (adj.size() > std::numeric_limits<NodeIndex>::max()) {
625 return absl::InvalidArgumentError(
626 absl::StrFormat(
"Too many nodes: adj.size()=%v", adj.size()));
628 const NodeIndex num_nodes(adj.size());
629 std::vector<NodeIndex> indegree(
static_cast<size_t>(num_nodes), NodeIndex(0));
630 std::vector<NodeIndex> topo_order;
631 topo_order.reserve(
static_cast<size_t>(num_nodes));
632 for (NodeIndex from(0); from < num_nodes; ++from) {
633 for (
const NodeIndex head : adj[from]) {
634 if (!(NodeIndex(0) <= head && head < num_nodes)) {
635 return absl::InvalidArgumentError(
636 absl::StrFormat(
"Invalid arc in adj[%v]: %v (num_nodes=%v)", from,
642 ++indegree[
static_cast<size_t>(head)];
645 for (NodeIndex i(0); i < num_nodes; ++i) {
646 if (!indegree[
static_cast<size_t>(i)]) topo_order.push_back(i);
648 size_t num_visited = 0;
649 while (num_visited < topo_order.size()) {
650 const NodeIndex from = topo_order[num_visited++];
651 for (
const NodeIndex head : adj[from]) {
652 if (!--indegree[
static_cast<size_t>(head)]) topo_order.push_back(head);
655 if (topo_order.size() <
static_cast<size_t>(num_nodes)) {
656 return absl::InvalidArgumentError(
"The graph has a cycle");
661template <
class AdjacencyLists>
663 std::vector<typename util::GraphTraits<AdjacencyLists>::NodeIndex>>
666 if (adj.size() > std::numeric_limits<NodeIndex>::max()) {
667 return absl::InvalidArgumentError(
668 absl::StrFormat(
"Too many nodes: adj.size()=%v", adj.size()));
670 const NodeIndex num_nodes(adj.size());
673 for (NodeIndex node(0); node < NodeIndex(node); ++node) {
674 for (
const NodeIndex head : adj[node]) {
675 if (head >= num_nodes) {
676 return absl::InvalidArgumentError(
677 absl::StrFormat(
"Invalid child %v in adj[%v]", head, node));
686 std::vector<bool> no_cycle_reachable_from(
static_cast<size_t>(num_nodes),
693 decltype(adj[NodeIndex(0)].begin()) children;
694 decltype(adj[NodeIndex(0)].end()) children_end;
696 explicit DfsState(NodeIndex _node,
697 const decltype(adj[NodeIndex(0)])& neighbours)
699 children(neighbours.begin()),
700 children_end(neighbours.end()) {}
702 std::vector<DfsState> dfs_stack;
703 std::vector<bool> visited(
static_cast<size_t>(num_nodes),
false);
704 for (NodeIndex start_node(0); start_node < NodeIndex(num_nodes);
706 if (no_cycle_reachable_from[
static_cast<size_t>(start_node)])
continue;
709 visited[
static_cast<size_t>(start_node)] =
true;
710 dfs_stack.push_back(DfsState(start_node, adj[start_node]));
711 while (!dfs_stack.empty()) {
712 DfsState*
const cur_state = &dfs_stack.back();
714 cur_state->children != cur_state->children_end &&
715 no_cycle_reachable_from[
static_cast<size_t>(*cur_state->children)]) {
716 ++cur_state->children;
718 if (cur_state->children == cur_state->children_end) {
719 no_cycle_reachable_from[
static_cast<size_t>(cur_state->node)] =
true;
720 dfs_stack.pop_back();
724 const NodeIndex child = *cur_state->children;
733 if (no_cycle_reachable_from[
static_cast<size_t>(child)])
continue;
734 if (visited[
static_cast<size_t>(child)]) {
737 size_t cycle_start = dfs_stack.size() - 1;
738 while (dfs_stack[cycle_start].node != child) --cycle_start;
739 const size_t cycle_size = dfs_stack.size() - cycle_start;
740 std::vector<NodeIndex> cycle(cycle_size);
741 for (
size_t c = 0; c < cycle_size; ++c) {
742 cycle[c] = dfs_stack[cycle_start + c].node;
748 dfs_stack.push_back(DfsState(child, adj[child]));
749 visited[
static_cast<size_t>(child)] =
true;
754 return std::vector<NodeIndex>{};
static StaticGraph FromArcs(NodeIndexType num_nodes, const ArcContainer &arcs)
Shortcut to directly create a finalized graph, i.e. Build() is called.
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
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.
absl::InlinedVector< int, 4 > AdjacencyList
To store the adjacency lists efficiently.
void ExtractCycle(std::vector< int > *cycle_nodes) const
To extract a cycle. When there is no cycle, cycle_nodes will be empty.
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)
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
std::decay_t< decltype(*(std::declval< NeighborRangeType >().begin()))> NodeIndex
The index type for nodes of the graph.
::util::DenseIntStableTopologicalSorter DenseIntStableTopologicalSorter
::util::DenseIntTopologicalSorter DenseIntTopologicalSorter