84 lines
3.0 KiB
C++
84 lines
3.0 KiB
C++
// 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 <functional>
|
|
#include <queue>
|
|
#include <vector>
|
|
|
|
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<int> 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<int>* output_cycle_nodes);
|
|
|
|
private:
|
|
// Finds the cycle.
|
|
void FindCycle(std::vector<int>* cycle_nodes);
|
|
|
|
const int num_nodes_;
|
|
// Outoging adjacency lists.
|
|
std::vector<std::vector<int>> adjacency_lists_;
|
|
|
|
// If true, no more AddEdge() can be called.
|
|
bool traversal_started_ = false;
|
|
int num_nodes_left_;
|
|
std::priority_queue<int, std::vector<int>, std::greater<int>>
|
|
nodes_with_zero_indegree_;
|
|
std::vector<int> indegree_;
|
|
};
|
|
|
|
} // namespace mediapipe
|
|
|
|
#endif // MEDIAPIPE_DEPS_TOPOLOGICALSORTER_H_
|