SMT-RAT  24.02
Toolbox for Strategic and Parallel Satisfiability-Modulo-Theories Solving
TikzHistoryPrinter.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <carl-common/datastructures/carlTree.h>
4 
5 #include <optional>
6 
7 #include <fstream>
8 #include <map>
9 #include <sstream>
10 
11 namespace smtrat {
12 namespace cad {
13 namespace debug {
14 
15 struct IDSanitizer {
16 private:
17  std::map<std::string,std::string> mMap;
18  std::string mPrefix;
19 public:
20  IDSanitizer(const std::string& prefix): mPrefix(prefix) {}
21  std::string operator()(const std::string& raw) {
22  auto it = mMap.find(raw);
23  if (it == mMap.end()) {
24  it = mMap.emplace(raw, mPrefix + "_" + std::to_string(mMap.size())).first;
25  }
26  return it->second;
27  }
28 };
29 
30 struct UnifiedData {
31  std::vector<std::optional<std::string>> steps;
32 
33  void add(std::size_t step, const std::string& data) {
34  while (steps.size() < step) steps.emplace_back();
35  steps.emplace_back(data);
36  }
37  bool showsOn(std::size_t step) const {
38  if (step >= steps.size()) return false;
39  return bool(steps[step]);
40  }
41  const std::string& data(std::size_t step) const {
42  assert(steps.size() > step);
43  assert(steps[step]);
44  return *steps[step];
45  }
46 };
47 
49 protected:
50  std::size_t mStep;
51  std::string printableID(const std::string& raw, const std::string& prefix, std::map<std::string,std::string>& map) const {
52  auto it = map.find(raw);
53  if (it == map.end()) {
54  it = map.emplace(raw, prefix + "_" + std::to_string(map.size())).first;
55  }
56  return it->second;
57  }
58 public:
59  virtual void addNode(std::size_t level, const std::string& parent, const std::string& node, const std::string& data) = 0;
60  virtual void addEdge(const std::string& src, const std::string& dst, const std::string& data) = 0;
61  void step() {
62  mStep++;
63  }
64  virtual void layout() = 0;
65  virtual void writeTo(std::ostream& os, int xBase) const = 0;
66 
67  virtual std::size_t width() const = 0;
68 };
69 
71 private:
72  struct Node {
74  std::map<std::string, UnifiedData> outgoing;
75  };
76  using Level = std::map<std::string, Node>;
77  using NodeIDs = std::map<std::string, Level::iterator>;
78  std::vector<Level> mData;
80  std::size_t mMaxWidth = 0;
81 public:
82  void addNode(std::size_t level, const std::string&, const std::string& node, const std::string& data) override {
83  while (level >= mData.size()) mData.emplace_back();
84  auto it = mNodeIDs.find(node);
85  if (it == mNodeIDs.end()) {
86  auto newIt = mData[level].emplace(node, Node()).first;
87  it = mNodeIDs.emplace(node, newIt).first;
88  }
89  it->second->second.data.add(mStep, data);
90  }
91  void addEdge(const std::string& src, const std::string& dst, const std::string& data) override {
92  auto it = mNodeIDs.find(src);
93  assert(it != mNodeIDs.end());
94  auto outid = it->second->second.outgoing.find(dst);
95  if (outid == it->second->second.outgoing.end()) {
96  outid = it->second->second.outgoing.emplace(dst, UnifiedData()).first;
97  }
98  outid->second.add(mStep, data);
99  }
100 
101  void layout() override {
102  for (const auto& l: mData) {
103  mMaxWidth = std::max(mMaxWidth, l.size() * 5);
104  }
105  }
106  void writeTo(std::ostream& os, int xBase) const override {
107  IDSanitizer sanitizer("projection");
108  for (std::size_t level = 0; level < mData.size(); level++) {
109  int curX = 0;
110  int increment = 0;
111  if (mData[level].size() > 1) {
112  increment = int(mMaxWidth / (mData[level].size() - 1));
113  }
114  for (const auto& entry: mData[level]) {
115  for (std::size_t step = 0; step < mStep; step++) {
116  if (!entry.second.data.showsOn(step)) continue;
117  std::size_t cur = step;
118  while (cur < mStep && entry.second.data.showsOn(cur) && entry.second.data.data(cur) == entry.second.data.data(step)) cur++;
119  os << "\t\\onslide<" << (step+1) << "-" << (cur+1) << ">{" << std::endl;
120  os << "\t\t\\node [align=center] (" << sanitizer(entry.first) << ") at (" << (xBase + curX) << "," << level << ") {" << entry.second.data.data(step) << "};"<< std::endl;
121  os << "\t};" << std::endl;
122  step = cur;
123  }
124  curX += increment;
125  for (const auto& edge: entry.second.outgoing) {
126  for (std::size_t step = 0; step < mStep; step++) {
127  if (!edge.second.showsOn(step)) continue;
128  std::size_t cur = step;
129  while (cur < mStep && edge.second.showsOn(cur) && edge.second.data(cur) == edge.second.data(step)) cur++;
130  os << "\t\\onslide<" << (step+1) << "-" << (cur+1) << ">{" << std::endl;
131  os << "\t\t\\path (" << sanitizer(entry.first) << ") edge (" << sanitizer(edge.first) << ") node {" << edge.second.data(step) << "};" << std::endl;
132  os << "\t};" << std::endl;
133  step = cur;
134  }
135  }
136  }
137  }
138  }
139 
140  std::size_t width() const override {
141  return mMaxWidth;
142  }
143 };
144 
146 private:
147  struct UnifiedNode {
149  std::string id;
150  std::size_t depth = 0;
151  std::size_t subtreeWidth = 0;
152  int position = 0;
153 
154  void add(std::size_t step, const std::string& data) {
155  mData.add(step, data);
156  }
157  bool showsOn(std::size_t step) const {
158  return mData.showsOn(step);
159  }
160  const std::string& data(std::size_t step) const {
161  return mData.data(step);
162  }
163  friend std::ostream& operator<<(std::ostream& os, const UnifiedNode& un) {
164  return os << un.subtreeWidth << " @ " << un.id;
165  }
166  };
167  using Tree = carl::tree<UnifiedNode>;
168  using TreeIDs = std::map<std::string, Tree::iterator>;
169  using Edges = std::map<std::pair<std::string,std::string>, UnifiedData>;
173 
174  void doLayout(const Tree::iterator& it) {
175  int cur = it->position - int(it->subtreeWidth / 2);
176  for (auto cit = mTree.begin_children(it); cit != mTree.end_children(it); cit++) {
177  cit->position = cur + int(cit->subtreeWidth / 2);
178  doLayout(cit);
179  cur += int(cit->subtreeWidth);
180  }
181  }
182  template<typename It>
183  void reorderTree(Tree& newTree, const It& source, const It& target) const {
184  std::vector<It> children;
185  for (auto it = mTree.begin_children(source); it != mTree.end_children(source); it++) {
186  children.push_back(it);
187  }
188  std::sort(children.begin(), children.end(), [](auto l, auto r){ return l->id < r->id; });
189  for (const auto& c: children) {
190  auto it = newTree.append(target, *c);
191  reorderTree(newTree, c, it);
192  }
193  }
194 public:
195  void setRoot(const std::string& node, const std::string& data) {
196  auto it = mTreeIDs.find(node);
197  if (it == mTreeIDs.end()) {
198  auto rit = mTree.setRoot(UnifiedNode());
199  it = mTreeIDs.emplace(node, rit).first;
200  it->second->id = node;
201  }
202  it->second->add(mStep, data);
203  }
204  void addNode(std::size_t level, const std::string& parent, const std::string& node, const std::string& data) override {
205  if (level == 0) return setRoot(node, data);
206  auto pit = mTreeIDs.at(parent);
207  auto nit = mTreeIDs.find(node);
208  if (nit == mTreeIDs.end()) {
209  auto newit = mTree.append(pit, UnifiedNode());
210  nit = mTreeIDs.emplace(node, newit).first;
211  nit->second->id = node;
212  }
213  assert(mTree.get_parent(nit->second) == pit);
214  assert(nit->second.depth() == level);
215  nit->second->add(mStep, data);
216  }
217  void addEdge(const std::string& src, const std::string& dst, const std::string& data) override {
218  auto it = mEdges.find(std::make_pair(src,dst));
219  if (it == mEdges.end()) {
220  it = mEdges.emplace(std::make_pair(src,dst), UnifiedData()).first;
221  }
222  it->second.add(mStep, data);
223  }
224  void layout() override {
225  Tree newTree;
226  newTree.setRoot(*mTree.begin());
227  reorderTree(newTree, mTree.begin(), newTree.begin());
228  mTree = newTree;
229  for (auto it = mTree.begin_postorder(); it != mTree.end_postorder(); it++) {
230  it->subtreeWidth = 0;
231  for (auto cit = mTree.begin_children(it); cit != mTree.end_children(it); cit++) {
232  it->subtreeWidth += cit->subtreeWidth;
233  }
234  if (it->subtreeWidth == 0) it->subtreeWidth = 1;
235  }
236  mTree.begin()->position = 0;
237  doLayout(mTree.begin());
238  }
239  void writeTo(std::ostream& os, int xBase) const override {
240  IDSanitizer sanitizer("lifting");
241  for (auto it = mTree.begin(); it != mTree.end(); it++) {
242  for (std::size_t step = 0; step < mStep; step++) {
243  if (!it->showsOn(step)) continue;
244  std::size_t cur = step;
245  while (cur < mStep && it->showsOn(cur) && it->data(cur) == it->data(step)) cur++;
246  os << "\t\\onslide<" << (step+1) << "-" << (cur+1) << ">{" << std::endl;
247  os << "\t\t\\node [align=center] (" << sanitizer(it->id) << ") at (" << (xBase + it->position) << "," << it.depth() << ") {" << it->data(step) << "};"<< std::endl;
248  os << "\t};" << std::endl;
249  step = cur;
250  }
251  }
252  for (const auto& e: mEdges) {
253  for (std::size_t step = 0; step < mStep; step++) {
254  if (!e.second.showsOn(step)) continue;
255  std::size_t cur = step;
256  while (cur < mStep && e.second.showsOn(cur) && e.second.data(cur) == e.second.data(step)) cur++;
257  os << "\t\\onslide<" << (step+1) << "-" << (cur+1) << ">{" << std::endl;
258  os << "\t\t\\path (" << sanitizer(e.first.first) << ") edge (" << sanitizer(e.first.second) << ") node {" << e.second.data(step) << "};" << std::endl;
259  os << "\t};" << std::endl;
260  step = cur;
261  }
262  }
263  }
264  virtual std::size_t width() const override {
265  return mTree.begin()->subtreeWidth;
266  }
267 };
268 
270 private:
271  std::map<std::string, TikzBasePrinter*> mPrinter;
272  std::size_t mStep = 0;
273 
274  TikzBasePrinter* getPrinter(const std::string& id) {
275  return mPrinter.at(id);
276  }
277  template<typename T>
278  std::string asString(const T& t) const {
279  std::stringstream ss;
280  ss << t;
281  return ss.str();
282  }
283  std::string nodeValue(const Sample& s, bool asTex = false) const {
284  std::stringstream ss;
285  if (asTex) ss << "$";
286  if (s.value().is_numeric()) ss << s.value().value();
287  else ss << s.value().interval();
288  if (asTex) {
289  if (s.isRoot()) ss << "_R";
290  ss << "$";
291  }
292  return ss.str();
293  }
294  std::string sampleID(const Sample& s) const {
295  double val = 0;
296  if (s.value().is_numeric()) val = carl::to_double(s.value().value());
297  else val = carl::to_double(carl::center(s.value().interval()));
298  if (val < 0) val = -1 / (val - 1);
299  else val = val + 1;
300  return std::to_string(val);
301  }
302  template<typename Tree, typename It>
303  std::string nodeID(const Tree& t, const It& it) const {
304  std::stringstream ss;
305  for (auto i = t.begin_path(it); i != t.end_path(); i++) {
306  ss << sampleID(*i) << "/";
307  }
308  return ss.str();
309  }
310  std::string polyID(std::size_t level, std::size_t id) const {
311  return std::to_string(level) + "_" + std::to_string(id);
312  }
313 public:
314  template<typename Printer>
315  void configure(const std::string& name) {
316  mPrinter.emplace(name, new Printer());
317  }
318 
319  template<typename ID1, typename ID2, typename T>
320  void addNode(const std::string& printer, std::size_t level, const ID1& parent, const ID2& node, const T& data) {
321  getPrinter(printer)->addNode(level, asString(parent), asString(node), asString(data));
322  }
323  template<typename ID1, typename ID2, typename T>
324  void addEdge(const std::string& printer, const ID1& src, const ID2& dst, const T& data) {
325  getPrinter(printer)->addEdge(asString(src), asString(dst), asString(data));
326  }
327 
328  template<typename L>
329  void addLifting(const L& l) {
330  const auto& t = l.getTree();
331  for (auto node = t.begin(); node != t.end(); node++) {
332  if (node.isRoot()) {
333  addNode("Lifting", node.depth(), "", nodeID(t, node), nodeValue(*node, true));
334  } else {
335  const auto& p = t.get_parent(node);
336  addNode("Lifting", node.depth(), nodeID(t, p), nodeID(t, node), nodeValue(*node, true));
337  addEdge("Lifting", nodeID(t, p), nodeID(t, node), "");
338  }
339  }
340  }
341  template<typename P>
342  void addProjection(const P& p) {
343  for (std::size_t level = 1; level <= p.dim(); level++) {
344  for (std::size_t id = 0; id < p.size(level); id++) {
345  if (!p.hasPolynomialById(level, id)) continue;
346  const auto& poly = p.getPolynomialById(level, id);
347  addNode("Projection", level, "", polyID(level, id), asString(poly));
348  if (level == 0) continue;
349  for (const auto& parent: p.getOrigin(level, id)) {
350  addEdge("Projection", polyID(parent.level, parent.first), polyID(level, id), "");
351  if (parent.first != parent.second) {
352  addEdge("Projection", polyID(parent.level, parent.second), polyID(level, id), "");
353  }
354  }
355  }
356  }
357  }
358 
359  void step() {
360  mStep++;
361  for (auto& p: mPrinter) p.second->step();
362  }
363 
364  void layout() {
365  for (auto& p: mPrinter) p.second->layout();
366  }
367 
368  void writeTo(const std::string& filename) const {
369  std::size_t width = 0;
370  for (auto& p: mPrinter) {
371  width += p.second->width();
372  }
373  std::ofstream out(filename);
374  out << "\\documentclass[8pt]{beamer}" << std::endl;
375  out << "\\usepackage{tikz}" << std::endl;
376  out << "\\tikzset{font=\\tiny}" << std::endl;
377  out << "\\setbeamertemplate{navigation symbols}{}" << std::endl;
378  out << "\\begin{document}" << std::endl;
379  out << "\\eject \\pdfpagewidth=" << (0.5*double(width) + 2) << "cm" << std::endl;
380  out << "\\begin{frame}<1-" << mStep << ">" << std::endl;
381  out << "\\begin{tikzpicture}[x=0.5cm, y=1cm]" << std::endl;
382  for (auto& p: mPrinter) {
383  p.second->writeTo(out, 0);
384  }
385  out << "\\end{tikzpicture}" << std::endl;
386  out << "\\end{frame}" << std::endl;
387  out << "\\end{document}" << std::endl;
388  }
389 };
390 
391 }
392 }
393 }
const RAN & value() const
Definition: Sample.h:30
bool isRoot() const
Definition: Sample.h:33
virtual void writeTo(std::ostream &os, int xBase) const =0
virtual void addEdge(const std::string &src, const std::string &dst, const std::string &data)=0
virtual std::size_t width() const =0
virtual void addNode(std::size_t level, const std::string &parent, const std::string &node, const std::string &data)=0
std::string printableID(const std::string &raw, const std::string &prefix, std::map< std::string, std::string > &map) const
void writeTo(std::ostream &os, int xBase) const override
std::map< std::string, Level::iterator > NodeIDs
std::size_t width() const override
void addEdge(const std::string &src, const std::string &dst, const std::string &data) override
std::map< std::string, Node > Level
void addNode(std::size_t level, const std::string &, const std::string &node, const std::string &data) override
std::string sampleID(const Sample &s) const
std::string asString(const T &t) const
std::string polyID(std::size_t level, std::size_t id) const
void addEdge(const std::string &printer, const ID1 &src, const ID2 &dst, const T &data)
void configure(const std::string &name)
TikzBasePrinter * getPrinter(const std::string &id)
std::map< std::string, TikzBasePrinter * > mPrinter
void addNode(const std::string &printer, std::size_t level, const ID1 &parent, const ID2 &node, const T &data)
std::string nodeID(const Tree &t, const It &it) const
void writeTo(const std::string &filename) const
std::string nodeValue(const Sample &s, bool asTex=false) const
void doLayout(const Tree::iterator &it)
void addNode(std::size_t level, const std::string &parent, const std::string &node, const std::string &data) override
std::map< std::pair< std::string, std::string >, UnifiedData > Edges
void setRoot(const std::string &node, const std::string &data)
void addEdge(const std::string &src, const std::string &dst, const std::string &data) override
virtual std::size_t width() const override
std::map< std::string, Tree::iterator > TreeIDs
void reorderTree(Tree &newTree, const It &source, const It &target) const
void writeTo(std::ostream &os, int xBase) const override
void sort(T *array, int size, LessThan lt)
Definition: Sort.h:67
std::vector< T > prefix(const std::vector< T > vars, std::size_t prefixSize)
Definition: utils.h:349
Class to create the formulas for axioms.
std::map< std::string, std::string > mMap
std::string operator()(const std::string &raw)
IDSanitizer(const std::string &prefix)
std::map< std::string, UnifiedData > outgoing
void add(std::size_t step, const std::string &data)
friend std::ostream & operator<<(std::ostream &os, const UnifiedNode &un)
const std::string & data(std::size_t step) const
const std::string & data(std::size_t step) const
std::vector< std::optional< std::string > > steps
void add(std::size_t step, const std::string &data)
bool showsOn(std::size_t step) const