// Copyright 2019 The MediaPipe Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef MEDIAPIPE_DEPS_TOPOLOGICALSORTER_H_ #define MEDIAPIPE_DEPS_TOPOLOGICALSORTER_H_ #include #include #include namespace mediapipe { // TopologicalSorter provides topologically sorted traversal of the nodes of a // directed acyclic graph (DAG) with up to INT_MAX nodes. The sorter requires // that all nodes and edges be added before traversing the nodes, otherwise it // will die with a fatal error. If a cycle is detected during the traversal, // the sorter will stop the traversal, and set the cycle_nodes vector. // // Sample usage: // TopologicalSorter sorter(num_nodes); // sorter.AddEdge(ObjToIndex(obj_a), ObjToIndex(obj_b)); // sorter.AddEdge(ObjToIndex(obj_a), ObjToIndex(obj_c)); // ... // sorter.AddEdge(ObjToIndex(obj_b), ObjToIndex(obj_c)); // int idx; // bool cyclic = false; // std::vector cycle_nodes; // while (sorter.GetNext(&idx, &cyclic, &cycle_nodes)) { // if (cyclic) { // PrintCycleNodes(cycle_nodes); // } else { // LOG(INFO) << idx; // } // } class TopologicalSorter { public: explicit TopologicalSorter(int num_nodes); TopologicalSorter(const TopologicalSorter&) = delete; TopologicalSorter& operator=(const TopologicalSorter&) = delete; // Adds a directed edge with the given endpoints to the graph. void AddEdge(int from, int to); // Visits the least node in topological order over the current set of // nodes and edges, and marks that node as visited. // The repeated calls to GetNext() will visit all nodes in order. Writes the // newly visited node into *node_index and returns true with *cyclic set to // false (assuming the graph has not yet been discovered to be cyclic). // Returns false if all nodes have been visited, or if the graph is // discovered to be cyclic, in which case *cyclic is also set to true. bool GetNext(int* node_index, bool* cyclic, std::vector* output_cycle_nodes); private: // Finds the cycle. void FindCycle(std::vector* cycle_nodes); const int num_nodes_; // Outoging adjacency lists. std::vector> adjacency_lists_; // If true, no more AddEdge() can be called. bool traversal_started_ = false; int num_nodes_left_; std::priority_queue, std::greater> nodes_with_zero_indegree_; std::vector indegree_; }; } // namespace mediapipe #endif // MEDIAPIPE_DEPS_TOPOLOGICALSORTER_H_