Caffe2 - C++ API
A deep learning, cross platform ML framework
Algorithms.h
1 //===- nomnigraph/Graph/Algorithms.h - Graph algorithms ---------*- C++ -*-===//
2 //
3 // TODO Licensing.
4 //
5 //===----------------------------------------------------------------------===//
6 //
7 // This file defines algorithms that only require Graph level annotations.
8 // Tarjans is defined.
9 //
10 //===----------------------------------------------------------------------===//
11 
12 #ifndef NOM_GRAPH_ALGORITHMS_H
13 #define NOM_GRAPH_ALGORITHMS_H
14 
15 #include "nomnigraph/Graph/Graph.h"
16 
17 #include <assert.h>
18 #include <unordered_map>
19 #include <unordered_set>
20 
21 namespace nom {
22 namespace algorithm {
23 
25 template <typename T, typename U>
26 std::vector<Subgraph<T, U>> tarjans(Graph<T, U> *g);
27 #include "nomnigraph/Graph/TarjansImpl.h"
28 
30 template <typename G>
31 void reachable(typename G::NodeRef root, typename G::NodeRef ignored,
32  std::unordered_set<typename G::NodeRef> *seen) {
33  seen->insert(root);
34  for (const auto &outEdge : root->getOutEdges()) {
35  auto &newNode = outEdge->head();
36  if (newNode != ignored && (seen->find(newNode) == seen->end())) {
37  reachable<G>(newNode, ignored, seen);
38  }
39  }
40 }
41 
60 template <typename G>
61 Graph<typename G::NodeRef, int>
62 dominatorTree(G *g, typename G::NodeRef source = nullptr) {
63  assert(g->getMutableNodes().size() > 0 &&
64  "Cannot find dominator tree of empty graph.");
65  if (!source) {
66  auto rootSCC = tarjans(g).back();
67  assert(rootSCC.getNodes().size() == 1 &&
68  "Cannot determine source node topologically, please specify one.");
69  for (auto &node : rootSCC.getNodes()) {
70  source = node;
71  break;
72  }
73  }
74 
75  std::unordered_set<typename G::NodeRef> allNodes;
76  Graph<typename G::NodeRef, int> tree;
77  std::unordered_map<typename G::NodeRef,
78  typename Graph<typename G::NodeRef, int>::NodeRef>
79  mapToTreeNode;
80  std::unordered_map<typename G::NodeRef,
81  std::unordered_set<typename G::NodeRef>>
82  dominatorMap;
83 
84  for (auto node : g->getMutableNodes()) {
85  mapToTreeNode[node] = tree.createNode(std::move(node));
86  if (node == source) {
87  continue;
88  }
89  dominatorMap[source].insert(node);
90  }
91 
92  for (const auto &node : g->getMutableNodes()) {
93  if (node == source) {
94  continue;
95  }
96  std::unordered_set<typename G::NodeRef> seen;
97  std::unordered_set<typename G::NodeRef> dominated;
98  reachable<G>(source, node, &seen);
99  for (auto testNode : dominatorMap[source]) {
100  if (seen.find(testNode) == seen.end() && testNode != node) {
101  dominated.insert(testNode);
102  }
103  }
104  dominatorMap[node] = dominated;
105  }
106 
107  std::unordered_set<typename G::NodeRef> nextPass;
108  nextPass.insert(source);
109 
110  while (nextPass.size()) {
111  for (auto parent : nextPass) {
112  for (auto child : dominatorMap[parent]) {
113  while (mapToTreeNode[child]->getInEdges().size()) {
114  tree.deleteEdge(mapToTreeNode[child]->getInEdges().front());
115  }
116  tree.createEdge(mapToTreeNode[parent], mapToTreeNode[child]);
117  if (dominatorMap.find(child) != dominatorMap.end()) {
118  nextPass.insert(child);
119  }
120  }
121  nextPass.erase(parent);
122  }
123  }
124 
125  return tree;
126 }
127 
129 template <typename G>
130 std::unordered_map<typename G::NodeRef, typename G::NodeRef>
131 immediateDominatorMap(G *g, typename G::NodeRef source = nullptr) {
132  std::unordered_map<typename G::NodeRef, typename G::NodeRef> idomMap;
133  auto idomTree = dominatorTree(g, source);
134  for (auto node : idomTree.getMutableNodes()) {
135  // Sanity check, really should never happen.
136  assert(node->getInEdges().size() <= 1 && "Invalid dominator tree generated from graph, cannot determing idom map.");
137  // In degenerate cases, or for the root node, we self dominate.
138  if (node->getInEdges().size() == 0) {
139  idomMap[node->data()] = node->data();
140  } else {
141  auto idom = node->getInEdges()[0]->tail();
142  idomMap[node->data()] = idom->data();
143  }
144  }
145  return idomMap;
146 }
147 
152 template <typename G>
153 std::unordered_map<typename G::NodeRef, std::unordered_set<typename G::NodeRef>>
154 dominanceFrontierMap(G *g, typename G::NodeRef source = nullptr) {
155  auto idomMap = immediateDominatorMap(g, source);
156  std::unordered_map<typename G::NodeRef, std::unordered_set<typename G::NodeRef>> domFrontierMap;
157  for (const auto node : g->getMutableNodes()) {
158  if (node->getInEdges().size() < 2) { continue; }
159  for (auto inEdge : node->getInEdges()) {
160  auto predecessor = inEdge->tail();
161  // This variable will track all the way up the dominator tree.
162  auto runner = predecessor;
163  while (runner != idomMap[node]) {
164  domFrontierMap[runner].insert(node);
165  runner = idomMap[runner];
166  }
167  }
168  }
169  return domFrontierMap;
170 }
171 
172 } // namespace algorithm
173 } // namespace nom
174 
175 #endif // NOM_GRAPH_ALGORITHMS_H
Definition: Caffe2.cc:16