Skip to main content

GraphPrinter.h File

STL-only pretty printers for hybrid graphs. More...

Included Headers

#include "graph/Graph.h" #include <cstddef> #include <memory> #include <sstream> #include <string> #include <utility> #include <vector>

Namespaces Index

namespacesimaai
namespaceneat
namespacegraph

Classes Index

classGraphPrinter

Pretty-printer for runtime Graph instances; emits text, dot, or mermaid. More...

structOptions

Render options controlling which fields and labels are emitted. More...

Description

STL-only pretty printers for hybrid graphs.

File Listing

The file content with the documentation metadata removed is:

1
6#pragma once
7
8#include "graph/Graph.h"
9
10#include <cstddef>
11#include <memory>
12#include <sstream>
13#include <string>
14#include <utility>
15#include <vector>
16
17namespace simaai::neat::graph {
18
28class GraphPrinter final {
29public:
35 struct Options {
36 bool show_index = true;
37 bool show_kind = true;
38 bool show_user_label = true;
39 bool show_backend = true;
40 bool show_ports = true;
41
42 std::size_t max_label_chars = 200;
43 std::size_t max_ports = 16;
44
45 bool dot_rankdir_lr = true;
46 std::string dot_graph_name = "sima_hybrid_graph";
47
48 bool mermaid_lr = true;
49 std::string mermaid_id_prefix = "n";
50 };
51
53 static std::string to_text(const Graph& g) {
54 return to_text(g, Options{});
55 }
57 static std::string to_text(const Graph& g, const Options& opt) {
58 std::ostringstream oss;
59 for (NodeId id = 0; id < g.node_count(); ++id) {
60 const auto& n = g.node(id);
61 if (!n)
62 continue;
63
64 if (opt.show_index)
65 oss << id << ") ";
66 if (opt.show_kind)
67 oss << n->kind();
68 if (opt.show_backend) {
69 oss << " [" << backend_name_(n->backend()) << "]";
70 }
71 if (opt.show_user_label) {
72 const std::string label = n->user_label();
73 if (!label.empty())
74 oss << " '" << truncate_(label, opt.max_label_chars) << "'";
75 }
76
77 if (opt.show_ports) {
78 oss << "\n in: " << join_ports_(n->input_ports(), opt.max_ports);
79 oss << "\n out: " << join_ports_(n->output_ports(), opt.max_ports);
80 }
81
82 if (id + 1 < g.node_count())
83 oss << "\n";
84 }
85 return oss.str();
86 }
87
89 static std::string to_dot(const Graph& g) {
90 return to_dot(g, Options{});
91 }
93 static std::string to_dot(const Graph& g, const Options& opt) {
94 std::ostringstream oss;
95 oss << "digraph " << dot_id_(opt.dot_graph_name) << " {\n";
96 if (opt.dot_rankdir_lr)
97 oss << " rankdir=LR;\n";
98 oss << " node [shape=box];\n";
99
100 for (NodeId id = 0; id < g.node_count(); ++id) {
101 const auto& n = g.node(id);
102 if (!n)
103 continue;
104
105 std::string label = node_label_(n, id, opt);
106 if (opt.show_ports) {
107 label += "\\n" + dot_escape_("in: " + join_ports_(n->input_ports(), opt.max_ports));
108 label += "\\n" + dot_escape_("out: " + join_ports_(n->output_ports(), opt.max_ports));
109 }
110
111 oss << " " << dot_node_id_(id) << " [label=\"" << dot_escape_(label) << "\"];\n";
112 }
113
114 for (const auto& e : g.edges()) {
115 const std::string label = g.port_name(e.from_port) + "->" + g.port_name(e.to_port);
116 oss << " " << dot_node_id_(e.from) << " -> " << dot_node_id_(e.to) << " [label=\""
117 << dot_escape_(label) << "\"];\n";
118 }
119
120 oss << "}\n";
121 return oss.str();
122 }
123
125 static std::string to_mermaid(const Graph& g) {
126 return to_mermaid(g, Options{});
127 }
129 static std::string to_mermaid(const Graph& g, const Options& opt) {
130 std::ostringstream oss;
131 oss << "flowchart " << (opt.mermaid_lr ? "LR" : "TD") << "\n";
132
133 for (NodeId id = 0; id < g.node_count(); ++id) {
134 const auto& n = g.node(id);
135 if (!n)
136 continue;
137
138 std::string label = node_label_(n, id, opt);
139 if (opt.show_ports) {
140 label += "\n" + ("in: " + join_ports_(n->input_ports(), opt.max_ports));
141 label += "\n" + ("out: " + join_ports_(n->output_ports(), opt.max_ports));
142 }
143
144 oss << " " << mermaid_node_id_(id, opt) << "[\"" << mermaid_escape_(label) << "\"]\n";
145 }
146
147 for (const auto& e : g.edges()) {
148 const std::string label = g.port_name(e.from_port) + "->" + g.port_name(e.to_port);
149 oss << " " << mermaid_node_id_(e.from, opt) << " -->|" << mermaid_escape_(label) << "| "
150 << mermaid_node_id_(e.to, opt) << "\n";
151 }
152
153 return oss.str();
154 }
155
156private:
157 static const char* backend_name_(Backend b) {
158 switch (b) {
160 return "pipeline";
161 case Backend::Stage:
162 return "stage";
163 }
164 return "unknown";
165 }
166
167 static std::string node_label_(const std::shared_ptr<Node>& n, std::size_t id,
168 const Options& opt) {
169 std::ostringstream oss;
170 if (opt.show_index)
171 oss << id << ") ";
172 if (opt.show_kind)
173 oss << n->kind();
174 if (opt.show_backend)
175 oss << " [" << backend_name_(n->backend()) << "]";
176 if (opt.show_user_label) {
177 const std::string label = n->user_label();
178 if (!label.empty())
179 oss << " '" << truncate_(label, opt.max_label_chars) << "'";
180 }
181 return oss.str();
182 }
183
184 static std::string join_ports_(const std::vector<PortDesc>& ports, std::size_t max_ports) {
185 if (ports.empty())
186 return "<none>";
187 std::ostringstream oss;
188 std::size_t count = 0;
189 for (const auto& p : ports) {
190 if (count++ > 0)
191 oss << ", ";
192 oss << p.name;
193 if (p.optional)
194 oss << "?";
195 if (count >= max_ports) {
196 if (ports.size() > max_ports)
197 oss << ", ...";
198 break;
199 }
200 }
201 return oss.str();
202 }
203
204 static std::string truncate_(const std::string& s, std::size_t max_len) {
205 if (s.size() <= max_len)
206 return s;
207 if (max_len < 3)
208 return s.substr(0, max_len);
209 return s.substr(0, max_len - 3) + "...";
210 }
211
212 static std::string dot_escape_(const std::string& s) {
213 std::string out;
214 out.reserve(s.size());
215 for (char c : s) {
216 if (c == '"')
217 out += "\\\"";
218 else if (c == '\\')
219 out += "\\\\";
220 else
221 out += c;
222 }
223 return out;
224 }
225
226 static std::string mermaid_escape_(const std::string& s) {
227 std::string out;
228 out.reserve(s.size());
229 for (char c : s) {
230 if (c == '"')
231 out += "\\\"";
232 else
233 out += c;
234 }
235 return out;
236 }
237
238 static std::string dot_id_(const std::string& s) {
239 if (s.empty())
240 return "graph";
241 return s;
242 }
243
244 static std::string dot_node_id_(std::size_t id) {
245 return "n" + std::to_string(id);
246 }
247
248 static std::string mermaid_node_id_(std::size_t id, const Options& opt) {
249 return opt.mermaid_id_prefix + std::to_string(id);
250 }
251};
252
253} // namespace simaai::neat::graph

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.9.8.