1
1
#ifndef NOM_CONVERTERS_DOT_H
2
2
#define NOM_CONVERTERS_DOT_H
3
3
4
+ #include " nomnigraph/Graph/Algorithms.h"
4
5
#include " nomnigraph/Graph/Graph.h"
5
6
#include " nomnigraph/Support/Casting.h"
6
7
10
11
#include < queue>
11
12
#include < sstream>
12
13
#include < unordered_map>
14
+ #include < vector>
13
15
14
16
namespace nom {
15
17
namespace converters {
16
18
17
- template <typename T, typename ... U >
19
+ template <typename GraphT >
18
20
class DotGenerator {
19
21
public:
20
22
using NodePrinter = std::function<std::map<std::string, std::string>(
21
- typename nom::Graph<T, U...> ::NodeRef)>;
23
+ typename GraphT ::NodeRef)>;
22
24
using EdgePrinter = std::function<std::map<std::string, std::string>(
23
- typename nom::Graph<T, U...>::EdgeRef)>;
24
- using NodeRef = typename nom::Graph<T, U...>::NodeRef;
25
+ typename GraphT::EdgeRef)>;
25
26
26
27
static std::map<std::string, std::string> defaultEdgePrinter (
27
- typename nom::Graph<T, U...>:: EdgeRef e ) {
28
+ typename GraphT:: EdgeRef) {
28
29
std::map<std::string, std::string> labelMap;
29
30
return labelMap;
30
31
}
31
32
32
- DotGenerator (typename nom::Graph<T, U...>* g) : g_(g) {}
33
+ DotGenerator (NodePrinter nodePrinter, EdgePrinter edgePrinter)
34
+ : nodePrinter_(nodePrinter), edgePrinter_(edgePrinter) {}
33
35
34
- ~DotGenerator () {}
35
-
36
- /* *
37
- * Converts given graph into DOT string
38
- * @param nodePrinter node attribute extractor
39
- * @param edgePrinter edge attribute extractor
40
- * @return DOT string representation of graph
41
- */
42
- std::string convert (NodePrinter nodePrinter, EdgePrinter edgePrinter) {
36
+ // Convert a graph (with optional subgraphs cluster) to dot.
37
+ std::string convert (
38
+ const typename GraphT::SubgraphType& sg,
39
+ const std::vector<typename GraphT::SubgraphType*>& subgraphs) const {
43
40
std::ostringstream output;
44
41
output << " digraph G {\n \
45
42
" ;
46
- for (const auto & node : g_->getMutableNodes ()) {
47
- output << (uint64_t )node; // dot doesn't like hex
48
- output << " [" ;
49
- for (const auto & attrib : nodePrinter (node)) {
50
- output << attrib.first << " =\" " << attrib.second << " \" ," ;
51
- }
52
- output << " ];\n " ;
53
- for (const auto & edge : node->getOutEdges ()) {
54
- output << (uint64_t )edge->tail () << " -> " << (uint64_t )edge->head ();
55
- output << " [" ;
56
- for (const auto & attrib : edgePrinter (edge)) {
57
- output << attrib.first << " =\" " << attrib.second << " \" ," ;
58
- }
59
- output << " ];\n " ;
60
- }
43
+ for (const auto & node : sg.getNodes ()) {
44
+ generateNode (node, sg, output);
61
45
}
62
- for (auto i = 0 ; i < subgraphs_ .size (); ++i) {
63
- const auto & subgraph = subgraphs_ [i];
46
+ for (auto i = 0 ; i < subgraphs .size (); ++i) {
47
+ const auto & subgraph = subgraphs [i];
64
48
output << " subgraph cluster" << i << " {\n " ;
65
49
output << " style=dotted;\n " ;
66
50
for (const auto & node : subgraph->getNodes ()) {
@@ -73,6 +57,18 @@ class DotGenerator {
73
57
return output.str ();
74
58
}
75
59
60
+ // Convert a subgraph to dot.
61
+ std::string convert (const typename GraphT::SubgraphType& sg) const {
62
+ std::ostringstream output;
63
+ output << " digraph G {\n \
64
+ " ;
65
+ for (const auto & node : sg.getNodes ()) {
66
+ generateNode (node, sg, output);
67
+ }
68
+ output << " }" ;
69
+ return output.str ();
70
+ }
71
+
76
72
/* *
77
73
* NOTE No subgraph support
78
74
* Converts given graph into DOT string w/operator input-order preserved
@@ -84,19 +80,20 @@ class DotGenerator {
84
80
* - Node: op_ptr[shape=record, label="{{<i0>*|<i1>*|...}|{op}|{<o0>*}"]
85
81
* - Edge: <parent_node_ptr>:<ref>:s -> <this_node_ptr>:<ref>:n
86
82
*/
87
- std::string convertStruct (NodePrinter nodePrinter, EdgePrinter edgePrinter) {
83
+ std::string convertStruct (const typename GraphT::SubgraphType& sg) const {
88
84
std::ostringstream output;
89
85
output << " digraph G {\n " ;
90
86
91
87
// Get input nodes (nodes w/o parents)
92
- std::unordered_map<NodeRef, int > nodeDepthMap; // Touched nodes for BFS
93
- std::queue<NodeRef> workList; // Init w/parentless nodes
94
- for (const auto & node : g_->getMutableNodes ()) {
88
+ std::unordered_map<typename GraphT::NodeRef, int >
89
+ nodeDepthMap; // Touched nodes for BFS
90
+ std::queue<typename GraphT::NodeRef> workList; // Init w/parentless nodes
91
+ for (const auto & node : sg.getNodes ()) {
95
92
if (node->getInEdges ().size () == 0 && node->getOutEdges ().size () > 0 ) {
96
93
// Add input node to dot string
97
94
output << (uint64_t )node << " [shape=record, label=\" {{Data In}|{<"
98
95
<< (uint64_t )node << " >" ;
99
- for (const auto & attr : nodePrinter (node)) {
96
+ for (const auto & attr : nodePrinter_ (node)) {
100
97
output << attr.second ;
101
98
}
102
99
output << " }}\" ]\n " ;
@@ -108,7 +105,7 @@ class DotGenerator {
108
105
}
109
106
110
107
// BFS to get operator nodes
111
- std::vector<NodeRef> ops;
108
+ std::vector<typename GraphT:: NodeRef> ops;
112
109
while (workList.size () > 0 ) {
113
110
const auto & node = workList.front ();
114
111
for (const auto & edge : node->getOutEdges ()) {
@@ -127,25 +124,21 @@ class DotGenerator {
127
124
}
128
125
129
126
// Finalize output
130
- output << getOperatorSubtreeDotString (ops, nodePrinter ) << " }\n " ;
127
+ output << getOperatorSubtreeDotString (ops) << " }\n " ;
131
128
return output.str ();
132
129
}
133
130
134
- void addSubgraph (const nom::Subgraph<T, U...>* s) {
135
- subgraphs_.emplace_back (s);
136
- }
137
-
138
131
private:
139
- typename nom::Graph<T, U...>* g_ ;
140
- typename std::vector< const nom::Subgraph<T, U...>*> subgraphs_ ;
132
+ NodePrinter nodePrinter_ ;
133
+ EdgePrinter edgePrinter_ ;
141
134
142
135
/* *
143
136
* Get DOT string record of given operator and DOT string of its input edges
144
137
* @param op operator to parse
145
138
* @param nodePrinter node attribute extractor
146
139
* @return '\n' sep string of operator & input edges
147
140
*/
148
- std::string getOperatorDotString (NodeRef op, NodePrinter nodePrinter) {
141
+ std::string getOperatorDotString (typename GraphT:: NodeRef op) const {
149
142
std::ostringstream output;
150
143
std::ostringstream record; // Operator node record
151
144
record << (uint64_t )op << " [shape=record, label=\" {{" ;
@@ -167,15 +160,15 @@ class DotGenerator {
167
160
168
161
// Add input to operator record
169
162
record << sep << " <" << (uint64_t )input << " >" ;
170
- for (const auto & attr : nodePrinter (input)) {
163
+ for (const auto & attr : nodePrinter_ (input)) {
171
164
record << attr.second ;
172
165
}
173
166
sep = " |" ;
174
167
}
175
168
176
169
// Extract operator name
177
170
record << " }|{" ;
178
- for (const auto & attr : nodePrinter (op)) {
171
+ for (const auto & attr : nodePrinter_ (op)) {
179
172
record << attr.second ;
180
173
}
181
174
record << " }|{" ;
@@ -185,7 +178,7 @@ class DotGenerator {
185
178
for (const auto & edge : op->getOutEdges ()) {
186
179
const auto & child = edge->head ();
187
180
record << sep << " <" << (uint64_t )child << " >" ;
188
- for (const auto & attr : nodePrinter (child)) {
181
+ for (const auto & attr : nodePrinter_ (child)) {
189
182
record << attr.second ;
190
183
}
191
184
sep = " |" ;
@@ -203,48 +196,81 @@ class DotGenerator {
203
196
* @return DOT string that renders operators subgraph
204
197
*/
205
198
std::string getOperatorSubtreeDotString (
206
- std::vector<NodeRef> ops,
207
- NodePrinter nodePrinter) {
199
+ std::vector<typename GraphT::NodeRef> ops) const {
208
200
std::ostringstream output;
209
201
for (const auto & op : ops) {
210
- output << getOperatorDotString (op, nodePrinter );
202
+ output << getOperatorDotString (op);
211
203
}
212
204
return output.str ();
213
205
}
206
+
207
+ // Generate dot string for a node.
208
+ void generateNode (
209
+ typename GraphT::NodeRef node,
210
+ const typename GraphT::SubgraphType& sg,
211
+ std::ostringstream& output) const {
212
+ output << (uint64_t )node; // dot doesn't like hex
213
+ output << " [" ;
214
+ for (const auto & attrib : nodePrinter_ (node)) {
215
+ output << attrib.first << " =\" " << attrib.second << " \" ," ;
216
+ }
217
+ output << " ];\n " ;
218
+ for (const auto & edge : node->getOutEdges ()) {
219
+ if (!sg.hasEdge (edge)) {
220
+ continue ;
221
+ }
222
+ output << (uint64_t )edge->tail () << " -> " << (uint64_t )edge->head ();
223
+ output << " [" ;
224
+ for (const auto & attrib : edgePrinter_ (edge)) {
225
+ output << attrib.first << " =\" " << attrib.second << " \" ," ;
226
+ }
227
+ output << " ];\n " ;
228
+ }
229
+ }
214
230
};
215
231
216
- template <typename T, typename ... U>
232
+ // Convert a graph to dot string.
233
+ template <typename GraphT>
217
234
std::string convertToDotString (
218
- nom::Graph<T, U...> * g,
219
- typename DotGenerator<T, U... >::NodePrinter nodePrinter,
220
- typename DotGenerator<T, U... >::EdgePrinter edgePrinter =
221
- DotGenerator<T, U... >::defaultEdgePrinter) {
222
- auto d = DotGenerator<T, U...>(g );
223
- return d.convert (nodePrinter, edgePrinter );
235
+ GraphT * g,
236
+ typename DotGenerator<GraphT >::NodePrinter nodePrinter,
237
+ typename DotGenerator<GraphT >::EdgePrinter edgePrinter =
238
+ DotGenerator<GraphT >::defaultEdgePrinter) {
239
+ auto d = DotGenerator<GraphT>(nodePrinter, edgePrinter );
240
+ return d.convert (algorithm::createSubgraph (g), {} );
224
241
}
225
242
226
- template <typename T, typename ... U>
243
+ // Convert a graph to dot string and annotate subgraph clusters.
244
+ template <typename GraphT>
227
245
std::string convertToDotString (
228
- nom::Graph<T, U...>* g,
229
- const std::vector<nom::Subgraph<T, U...>>& subgraphs,
230
- typename DotGenerator<T, U...>::NodePrinter nodePrinter,
231
- typename DotGenerator<T, U...>::EdgePrinter edgePrinter =
232
- DotGenerator<T, U...>::defaultEdgePrinter) {
233
- auto d = DotGenerator<T, U...>(g);
234
- for (const auto & subgraph : subgraphs) {
235
- d.addSubgraph (&subgraph);
236
- }
237
- return d.convert (nodePrinter, edgePrinter);
246
+ GraphT* g,
247
+ const std::vector<typename GraphT::SubgraphType*>& subgraphs,
248
+ typename DotGenerator<GraphT>::NodePrinter nodePrinter,
249
+ typename DotGenerator<GraphT>::EdgePrinter edgePrinter =
250
+ DotGenerator<GraphT>::defaultEdgePrinter) {
251
+ auto d = DotGenerator<GraphT>(nodePrinter, edgePrinter);
252
+ return d.convert (algorithm::createSubgraph (g), subgraphs);
253
+ }
254
+
255
+ // Convert a subgraph to dot string.
256
+ template <typename GraphT>
257
+ std::string convertToDotString (
258
+ const typename GraphT::SubgraphType& sg,
259
+ typename DotGenerator<GraphT>::NodePrinter nodePrinter,
260
+ typename DotGenerator<GraphT>::EdgePrinter edgePrinter =
261
+ DotGenerator<GraphT>::defaultEdgePrinter) {
262
+ auto d = DotGenerator<GraphT>(nodePrinter, edgePrinter);
263
+ return d.convert (sg);
238
264
}
239
265
240
- template <typename T, typename ... U >
266
+ template <typename GraphT >
241
267
std::string convertToDotRecordString (
242
- nom::Graph<T, U...> * g,
243
- typename DotGenerator<T, U... >::NodePrinter nodePrinter,
244
- typename DotGenerator<T, U... >::EdgePrinter edgePrinter =
245
- DotGenerator<T, U... >::defaultEdgePrinter) {
246
- auto d = DotGenerator<T, U...>(g );
247
- return d.convertStruct (nodePrinter, edgePrinter );
268
+ GraphT * g,
269
+ typename DotGenerator<GraphT >::NodePrinter nodePrinter,
270
+ typename DotGenerator<GraphT >::EdgePrinter edgePrinter =
271
+ DotGenerator<GraphT >::defaultEdgePrinter) {
272
+ auto d = DotGenerator<GraphT>(nodePrinter, edgePrinter );
273
+ return d.convertStruct (algorithm::createSubgraph (g) );
248
274
}
249
275
250
276
} // namespace converters
0 commit comments