Caffe2 - C++ API
A deep learning, cross platform ML framework
Graph.h
1 //===- nomnigraph/Graph/Graph.h - Basic graph implementation ----*- C++ -*-===//
2 //
3 // TODO Licensing.
4 //
5 //===----------------------------------------------------------------------===//
6 //
7 // This file defines a basic graph API for generic and flexible use with
8 // graph algorithms.
9 //
10 //===----------------------------------------------------------------------===//
11 
12 #ifndef NOM_GRAPH_GRAPH_H
13 #define NOM_GRAPH_GRAPH_H
14 
15 #include "nomnigraph/Support/Common.h"
16 
17 #include <algorithm>
18 #include <iterator>
19 #include <list>
20 #include <unordered_set>
21 #include <vector>
22 
23 #include <stdio.h>
24 #include <assert.h>
25 
26 #define DEBUG_PRINT(...) ;
27 
28 namespace nom {
29 
30 template <typename T, typename U = T> class Graph;
31 
32 template <typename T, typename U = T> class Node;
33 
34 template <typename T, typename U = T> class Edge : public StorageType<U> {
35 public:
36  using NodeRef = typename Graph<T, U>::NodeRef;
37  using EdgeRef = typename Graph<T, U>::EdgeRef;
38 
39  Edge(NodeRef tail, NodeRef head) : Tail(tail), Head(head) {
40  DEBUG_PRINT("Creating instance of Edge: %p\n", this);
41  }
42 
43  Edge(NodeRef tail, NodeRef head, U &&data)
44  : StorageType<U>(std::move(data)), Tail(tail), Head(head) {
45  DEBUG_PRINT("Creating instance of Edge: %p\n", this);
46  }
47 
48  const NodeRef &tail() const { return Tail; }
49  const NodeRef &head() const { return Head; }
50 
51 private:
52  NodeRef Tail;
53  NodeRef Head;
54  friend class Graph<T, U>;
55 };
56 
57 template <typename T, typename U /* optional */>
58 class Node : public StorageType<T>, public Notifier<Node<T, U>> {
59 public:
61  explicit Node(T &&data) : StorageType<T>(std::move(data)) {
62  DEBUG_PRINT("Creating instance of Node: %p\n", this);
63  }
65  explicit Node() : StorageType<T>() {}
66 
67  using NodeRef = typename Graph<T, U>::NodeRef;
68  using EdgeRef = typename Graph<T, U>::EdgeRef;
69 
72  void addInEdge(EdgeRef e) { inEdges.emplace_back(e); }
73 
76  void addOutEdge(EdgeRef e) { outEdges.emplace_back(e); }
77 
80  void removeInEdge(EdgeRef e) {
81  auto iter = std::find(inEdges.begin(), inEdges.end(), e);
82  inEdges.erase(iter);
83  }
84 
87  void removeOutEdge(EdgeRef e) {
88  auto iter = std::find(outEdges.begin(), outEdges.end(), e);
89  outEdges.erase(iter);
90  }
91 
92  const std::vector<EdgeRef> &getOutEdges() const { return outEdges; }
93  const std::vector<EdgeRef> &getInEdges() const { return inEdges; }
94 
95 protected:
96  std::vector<EdgeRef> inEdges;
97  std::vector<EdgeRef> outEdges;
98  friend class Graph<T, U>;
99 };
100 
110 template <typename T, typename U = T> class Subgraph {
111 public:
112  Subgraph() { DEBUG_PRINT("Creating instance of Subgraph: %p\n", this); }
113 
114  using NodeRef = typename Graph<T, U>::NodeRef;
115  using EdgeRef = typename Graph<T, U>::EdgeRef;
116 
117  void addNode(NodeRef n) { Nodes.insert(n); }
118  bool hasNode(NodeRef n) const { return Nodes.count(n) != 0; }
119  void removeNode(NodeRef n) { Nodes.erase(n); }
120 
121  void addEdge(EdgeRef e) { Edges.insert(e); }
122  bool hasEdge(EdgeRef n) const { return Edges.count(n) != 0; }
123  void removeEdge(EdgeRef e) { Edges.erase(e); }
124 
125  const std::unordered_set<NodeRef> &getNodes() const { return Nodes; }
126  const std::unordered_set<EdgeRef> &getEdges() const { return Edges; }
127 
128  void printEdges() {
129  for (const auto &edge : Edges) {
130  printf("Edge: %p (%p -> %p)\n", &edge, edge->tail(), edge->head());
131  }
132  }
133 
134  void printNodes() const {
135  for (const auto &node : Nodes) {
136  printf("Node: %p\n", node);
137  }
138  }
139 
140  std::unordered_set<NodeRef> Nodes;
141  std::unordered_set<EdgeRef> Edges;
142 };
143 
148 template <typename T, typename U /* optional */> class Graph {
149 public:
150  Graph() { DEBUG_PRINT("Creating instance of Graph: %p\n", this); }
151  Graph(const Graph &) = delete;
152  Graph(Graph &&) = default;
153  Graph& operator=(Graph &&) = default;
154  ~Graph() {}
155 
156  using NodeRef = Node<T, U> *;
157  using EdgeRef = Edge<T, U> *;
158  using NodeType = T;
159  using EdgeType = U;
160 
164  NodeRef createNode(T &&data) {
165  Nodes.emplace_back(Node<T, U>(std::move(data)));
166  DEBUG_PRINT("Creating node (%p)\n", &Nodes.back());
167  return &Nodes.back();
168  }
169 
170  void swapNode(NodeRef node, Graph<T, U> &otherGraph) {
171  std::list<Node<T, U>> &otherNodes = otherGraph.Nodes;
172  for (auto it = Nodes.begin(); it != Nodes.end(); ++it) {
173  if (&(*it) == node) {
174  otherNodes.splice(otherNodes.end(), Nodes, it, ++it);
175  break;
176  }
177  }
178  }
179 
180  void swapEdge(EdgeRef edge, Graph<T, U> &otherGraph) {
181  std::list<Edge<T, U>> &otherEdges = otherGraph.Edges;
182  for (auto it = Edges.begin(); it != Edges.end(); ++it) {
183  if (&(*it) == edge) {
184  otherEdges.splice(otherEdges.end(), Edges, it, ++it);
185  break;
186  }
187  }
188  }
189 
190  NodeRef createNode() {
191  Nodes.emplace_back(Node<T, U>());
192  DEBUG_PRINT("Creating node (%p)\n", &Nodes.back());
193  return &Nodes.back();
194  }
195 
203  void replaceNode(const NodeRef &old, const NodeRef &newTail,
204  const NodeRef &newHead_ = nullptr) {
205  // If no newHead is specified, make the tail the head as well.
206  // We are effectively replacing the node with one node in this case.
207  const NodeRef newHead = newHead_ ? newHead_ : newTail;
208  const auto inEdges = old->getInEdges();
209  const auto outEdges = old->getOutEdges();
210 
211  for (const auto &inEdge : inEdges) {
212  createEdge(inEdge->tail(), newTail);
213  }
214  for (const auto &inEdge : inEdges) {
215  deleteEdge(inEdge);
216  }
217 
218  for (const auto &outEdge : outEdges) {
219  createEdge(newHead, outEdge->head());
220  }
221  for (const auto &outEdge : outEdges) {
222  deleteEdge(outEdge);
223  }
224  }
225 
231  DEBUG_PRINT("Creating edge (%p -> %p)\n", tail, head);
232  Edges.emplace_back(Edge<T, U>(tail, head));
233  EdgeRef e = &Edges.back();
234  head->addInEdge(e);
235  tail->addOutEdge(e);
236  return e;
237  }
238 
239  EdgeRef createEdge(NodeRef tail, NodeRef head, U &&data) {
240  DEBUG_PRINT("Creating edge (%p -> %p)\n", tail, head);
241  Edges.emplace_back(Edge<T, U>(tail, head, std::move(data)));
242  EdgeRef e = &Edges.back();
243  head->addInEdge(e);
244  tail->addOutEdge(e);
245  return e;
246  }
247 
251  for (auto& inEdge : head->getInEdges()) {
252  if (inEdge->tail() == tail) {
253  return inEdge;
254  }
255  }
256  assert(0 && "Edge doesn't exist.");
257  return nullptr;
258  }
259 
264  void deleteNode(NodeRef n, bool deleteEdges = true) {
265  if (deleteEdges) {
266  for (auto &edge : n->inEdges) {
267  deleteEdge(edge);
268  }
269  for (auto &edge : n->outEdges) {
270  deleteEdge(edge);
271  }
272  }
273  for (auto i = Nodes.begin(); i != Nodes.end(); ++i) {
274  if (&*i == n) {
275  Nodes.erase(i);
276  break;
277  }
278  }
279  }
280 
283  void deleteEdge(EdgeRef e) {
284  e->Tail->removeOutEdge(e);
285  e->Head->removeInEdge(e);
286  for (auto i = Edges.begin(); i != Edges.end(); ++i) {
287  if (&*i == e) {
288  Edges.erase(i);
289  break;
290  }
291  }
292  }
293 
294  const std::vector<NodeRef> getMutableNodes() {
295  std::vector<NodeRef> v;
296  for (auto &n : Nodes) {
297  DEBUG_PRINT("Adding node to mutable output (%p)\n", &n);
298  v.emplace_back(&n);
299  }
300  return v;
301  }
302 
303  const std::vector<EdgeRef> getMutableEdges() {
304  std::vector<EdgeRef> v;
305  for (auto &e : Edges) {
306  DEBUG_PRINT("Adding edge to mutable output (%p)\n", &e);
307  v.emplace_back(&e);
308  }
309  return v;
310  }
311 
312  void printEdges() {
313  for (const auto &edge : Edges) {
314  printf("Edge: %p (%p -> %p)\n", &edge, edge.tail(), edge.head());
315  }
316  }
317 
318  void printNodes() const {
319  for (const auto &node : Nodes) {
320  printf("Node: %p\n", &node);
321  }
322  }
323 
324 private:
325  std::list<Node<T, U>> Nodes;
326  std::list<Edge<T, U>> Edges;
327 };
328 
329 } // namespace nom
330 
331 #endif // NOM_GRAPH_GRAPH_H
void removeOutEdge(EdgeRef e)
Removes an edge by reference to known out-edges.
Definition: Graph.h:87
Node(T &&data)
Create a node with data.
Definition: Graph.h:61
void addOutEdge(EdgeRef e)
Adds an edge by reference to known out-edges.
Definition: Graph.h:76
Effectively a constant reference to a graph.
Definition: Graph.h:110
NodeRef createNode(T &&data)
Creates a node and retains ownership of it.
Definition: Graph.h:164
This class enables a listener pattern.
Definition: Common.h:34
Definition: types.h:72
EdgeRef getEdge(NodeRef tail, NodeRef head)
Get a reference to the edge between two nodes if it exists.
Definition: Graph.h:250
void deleteNode(NodeRef n, bool deleteEdges=true)
Deletes a node from the graph.
Definition: Graph.h:264
Definition: Caffe2.cc:16
void deleteEdge(EdgeRef e)
Deletes a edge from the graph.
Definition: Graph.h:283
void addInEdge(EdgeRef e)
Adds an edge by reference to known in-edges.
Definition: Graph.h:72
void replaceNode(const NodeRef &old, const NodeRef &newTail, const NodeRef &newHead_=nullptr)
Replace a node in the graph with a generic set of nodes.
Definition: Graph.h:203
A simple graph implementation.
Definition: Graph.h:30
EdgeRef createEdge(NodeRef tail, NodeRef head)
Creates a directed edge and retains ownership of it.
Definition: Graph.h:230
Node()
Create an empty node.
Definition: Graph.h:65
void removeInEdge(EdgeRef e)
Removes an edge by reference to known in-edges.
Definition: Graph.h:80