Version: 1.0
output_generator.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020, the GRAPHGEN contributors, as
2 // shown by the AUTHORS file. All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
6 
7 #include "output_generator.h"
8 
9 #include <optional>
10 
11 #include "system_info.h"
12 
13 using namespace std;
14 
15 //void print_node(BinaryDrag<conact>::node *n, int i)
16 //{
17 // std::cout << std::string(i, '\t');
18 // if (n->data.t == conact::type::CONDITION) {
19 // std::cout << n->data.condition;
20 // }
21 // else {
22 // std::cout << ". ";
23 // auto v = n->data.actions();
24 //
25 // std::cout << v[0];
26 // for (size_t i = 1; i < v.size(); ++i) {
27 // std::cout << "," << v[i];
28 // }
29 // }
30 // std::cout << "\n";
31 //}
32 
33 string GetShape(char c) {
34  switch (c) {
35  case '!': return ", shape = doubleoctagon";
36  case '?': return ", shape = doublecircle";
37  default: return "";
38  }
39 }
40 
41 string GetNodeCode(const string& condition, bool with_root_id) {
42 
43  string real_condition = condition;
44  if (condition[0] == '!' || condition[0] == '?') {
45  real_condition = condition.substr(1);
46  }
47 
48  if (!with_root_id) {
49  size_t pos = real_condition.find("- ");
50  if (pos != string::npos) {
51  real_condition = real_condition.substr(pos + 2); // This assumes that there is a space between dash and condition name
52  }
53  }
54 
55  return " [label = \"" + real_condition + "\"" + GetShape(condition[0]) + "];\n";
56 }
57 
58 void GenerateDotCodeForDagRec(std::ostream& os,
60  std::map<BinaryDrag<conact>::node*, size_t>& printed_node,
61  std::vector<std::string>& links,
62  nodeid &id,
63  bool with_next,
64  bool with_root_id,
65  int tab) {
66  os << std::string(tab, '\t') << "node" << id.get();
67  if (n->isleaf()) {
68  // print leaf
69  os << " [label = \"";
70  vector<uint> actions = n->data.actions();
71  os << actions[0];
72  for (size_t i = 1; i < actions.size(); ++i) {
73  os << "," << actions[i];
74  }
75  if (with_next) {
76  os << " - " << n->data.next;
77  }
78  os << "\", shape = box];\n";
79  }
80  else {
81  os << GetNodeCode(n->data.condition, with_root_id);
82  tab++;
83 
84  if (printed_node.find(n->left) == printed_node.end()) {
85  // node not already printed
86  printed_node[n->left] = id.next();
87  os << string(tab, '\t') << "node" << printed_node[n] << " -> node" << printed_node[n->left] << " [label=\"0\"];\n";
88  GenerateDotCodeForDagRec(os, n->left, printed_node, links, id, with_next, with_root_id, tab);
89  }
90  else {
91  std::stringstream ss;
92  ss << "node" << printed_node[n] << " -> node" << printed_node[n->left] << " [label=\"0\", style=dotted];\n";
93  links.push_back(ss.str());
94  }
95 
96  if (printed_node.find(n->right) == printed_node.end()) {
97  // node not already printed
98  printed_node[n->right] = id.next();
99  os << string(tab, '\t') << "node" << printed_node[n] << " -> node" << printed_node[n->right] << " [label=\"1\"];\n";
100  GenerateDotCodeForDagRec(os, n->right, printed_node, links, id, with_next, with_root_id, tab);
101  }
102  else {
103  std::stringstream ss;
104  ss << "node" << printed_node[n] << " -> node" << printed_node[n->right] << " [label=\"1\", style=dotted];\n";
105  links.push_back(ss.str());
106  }
107  }
108 }
109 
110 // All nodes must have both children!
111 void GenerateDotCodeForDag(std::ostream& os, const BinaryDrag<conact>& bd, bool with_next, bool with_root_id) {
112  os << "digraph dag{\n"
113  "ranksep=" + conf.dot_ranksep_ + "\n" +
114  "bgcolor=" + conf.dot_background_color_ + "\n" +
115  "\tsubgraph tree{\n";
116  nodeid id;
117 
118  std::map<BinaryDrag<conact>::node*, size_t> printed_node; // = { { bd.roots_[0] } , 0 };
119  std::vector<std::string> links;
120 
121  for (size_t i = 0; i < bd.roots_.size(); ++i) {
122  string tmp = bd.roots_[i]->data.condition;
123  if (i == 0) {
124  bd.roots_[i]->data.condition = "!" + tmp; // "! -> identifies the root of the start tree"
125  }
126  else {
127  bd.roots_[i]->data.condition = "?" + to_string(i) + " - " + tmp; // "?" -> identifies tree's root
128  }
129  printed_node[bd.roots_[i]] = id.next();
130  GenerateDotCodeForDagRec(os, bd.roots_[i], printed_node, links, id, with_next, with_root_id, 2);
131  bd.roots_[i]->data.condition = tmp; // Turn the condition back to its original value
132  }
133 
134  os << "\t}\n";
135  for (size_t i = 0; i < links.size(); ++i) {
136  os << links[i];
137  }
138 
139  os << "}\n";
140 }
141 
142 string GetDotCallString(const std::string& code_path, const std::string& output_path = "")
143 {
144  string dot_call;
145 
146 #ifdef GRAPHGEN_WINDOWS
147  dot_call = "..\\tools\\dot\\dot -T" + conf.dot_output_format_.substr(1) + " \"" + code_path + "\"";
148 #endif
149 
150 #ifdef GRAPHGEN_LINUX
151  dot_call = "dot -T" + conf.dot_output_format_.substr(1) + " \"" + code_path + "\"";
152 #endif
153 
154  if (dot_call.length() == 0) {
155  throw std::runtime_error("Error in generating graph output: Unsupported operating system for using dot module of graphviz (Linux and Windows only).");
156  }
157 
158  if(output_path != ""){
159  dot_call += " -o \"" + output_path + "\"";
160  }
161 
162  return dot_call;
163 }
164 
165 string GetDotCallString(const filesystem::path& code_path, filesystem::path output_path = "") {
166  return GetDotCallString(code_path.string(), output_path.string());
167 }
168 
169 bool DrawDagOnFile(const string& base_filename, const BinaryDrag<conact> &t, DrawDagFlags flags) {
170 
171  bool with_next = flags & DrawDagFlags::WITH_NEXT;
172  bool verbose = flags & DrawDagFlags::VERBOSE;
173  bool delete_dotcode = flags & DrawDagFlags::DELETE_DOTCODE;
174  bool with_root_id = flags & DrawDagFlags::WITH_ROOT_ID;
175 
176  if (verbose) {
177  std::cout << "Drawing DAG: " << base_filename << ".. ";
178  }
179  filesystem::path code_path = conf.GetDotCodePath(base_filename);
180  filesystem::path pdf_path = conf.GetDotOutPath(base_filename);
181  ofstream os(code_path);
182  if (!os) {
183  if (verbose) {
184  std::cout << "Unable to generate " << code_path << ", stopped\n";
185  }
186  return false;
187  }
188  GenerateDotCodeForDag(os, t, with_next, with_root_id);
189  os.close();
190  if (0 != system(GetDotCallString(code_path, pdf_path).c_str())) {
191  if (verbose) {
192  std::cout << "Unable to generate " + pdf_path.string() + ", stopped\n";
193  }
194  return false;
195  }
196 
197  if (verbose) {
198  std::cout << "done\n";
199  }
200 
201  if (delete_dotcode) {
202  remove(code_path.string().c_str());
203  }
204  return true;
205 }
206 
207 bool DrawForestOnFile(const string& output_file, const LineForestHandler& lfh, DrawDagFlags flags)
208 {
209  bool result = DrawDagOnFile(output_file + "_main_forest", lfh.f_, flags | DrawDagFlags::WITH_NEXT | DrawDagFlags::WITH_ROOT_ID);
210  for (size_t i = 0; i < lfh.end_forests_.size(); ++i) {
211  result &= DrawDagOnFile(output_file + "_end_forest_" + to_string(i), lfh.end_forests_[i], flags | DrawDagFlags::WITH_ROOT_ID);
212  }
213 
214  return result;
215 }
A BinaryDrag is the GRAPHGEN implementation of a Binary Directed Rooted Acyclic Graph (DRAG in short)
Definition: drag.h:28
std::vector< node * > roots_
Definition: drag.h:58
bool DrawDagOnFile(const string &base_filename, const BinaryDrag< conact > &t, DrawDagFlags flags)
void GenerateDotCodeForDag(std::ostream &os, const BinaryDrag< conact > &bd, bool with_next, bool with_root_id)
string GetNodeCode(const string &condition, bool with_root_id)
string GetDotCallString(const std::string &code_path, const std::string &output_path="")
void GenerateDotCodeForDagRec(std::ostream &os, BinaryDrag< conact >::node *n, std::map< BinaryDrag< conact >::node *, size_t > &printed_node, std::vector< std::string > &links, nodeid &id, bool with_next, bool with_root_id, int tab)
bool DrawForestOnFile(const string &output_file, const LineForestHandler &lfh, DrawDagFlags flags)
string GetShape(char c)
DrawDagFlags
Flags for the DrawDagOnFile function.
@ DELETE_DOTCODE
Whether to delete or not the dot code used to draw the drag.
@ WITH_ROOT_ID
Whether to print root id or not.
@ WITH_NEXT
Whether to print next tree indexes inside leaves or not.
@ VERBOSE
Whether to display output messages or not.
std::string dot_background_color_
Definition: config_data.h:34
std::string dot_ranksep_
Definition: config_data.h:36
std::filesystem::path GetDotCodePath(const std::string &out_base_name)
Definition: config_data.h:90
std::filesystem::path GetDotOutPath(const std::string &out_base_name)
Definition: config_data.h:95
std::string dot_output_format_
Definition: config_data.h:35
Generates all the forests needed to handle one line of the image.
Definition: forest.h:51
BinaryDrag< conact > f_
Definition: forest.h:92
std::vector< BinaryDrag< conact > > end_forests_
Definition: forest.h:93
ConfigData conf
Definition: utilities.cpp:9