souffle  2.0.2-371-g6315b36
GraphUtils.h
Go to the documentation of this file.
1 /*
2  * Souffle - A Datalog Compiler
3  * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved
4  * Licensed under the Universal Permissive License v 1.0 as shown at:
5  * - https://opensource.org/licenses/UPL
6  * - <souffle root>/licenses/SOUFFLE-UPL.txt
7  */
8 
9 /************************************************************************
10  *
11  * @file GraphUtils.h
12  *
13  * A simple utility graph for conducting simple, graph-based operations.
14  *
15  ***********************************************************************/
16 
17 #pragma once
18 
20 #include <functional>
21 #include <map>
22 #include <ostream>
23 #include <set>
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 namespace souffle {
29 
30 /**
31  * A simple graph structure for graph-based operations.
32  */
33 template <typename Vertex, typename Compare = std::less<Vertex>>
34 class Graph {
35 public:
36  /**
37  * Adds a new edge from the given vertex to the target vertex.
38  */
39  void insert(const Vertex& from, const Vertex& to) {
40  insert(from);
41  insert(to);
42  _successors[from].insert(to);
43  _predecessors[to].insert(from);
44  }
45 
46  /**
47  * Adds a vertex.
48  */
49  void insert(const Vertex& vertex) {
50  auto iter = _vertices.insert(vertex);
51  if (iter.second) {
52  _successors.insert(std::make_pair(vertex, std::set<Vertex, Compare>()));
53  _predecessors.insert(std::make_pair(vertex, std::set<Vertex, Compare>()));
54  }
55  }
56 
57  /** Obtains a reference to the set of all vertices */
58  const std::set<Vertex, Compare>& vertices() const {
59  return _vertices;
60  }
61 
62  /** Returns the set of vertices the given vertex has edges to */
63  const std::set<Vertex, Compare>& successors(const Vertex& from) const {
64  return _successors.at(from);
65  }
66 
67  /** Returns the set of vertices the given vertex has edges from */
68  const std::set<Vertex, Compare>& predecessors(const Vertex& to) const {
69  return _predecessors.at(to);
70  }
71 
72  /** Determines whether the given vertex is present */
73  bool contains(const Vertex& vertex) const {
74  return _vertices.find(vertex) != _vertices.end();
75  }
76 
77  /** Determines whether the given edge is present */
78  bool contains(const Vertex& from, const Vertex& to) const {
79  auto pos = _successors.find(from);
80  if (pos == _successors.end()) {
81  return false;
82  }
83  auto p2 = pos->second.find(to);
84  return p2 != pos->second.end();
85  }
86 
87  /** Determines whether there is a directed path between the two vertices */
88  bool reaches(const Vertex& from, const Vertex& to) const {
89  // quick check
90  if (!contains(from) || !contains(to)) {
91  return false;
92  }
93 
94  // conduct a depth-first search starting at from
95  bool found = false;
96  bool first = true;
97  visitDepthFirst(from, [&](const Vertex& cur) {
98  found = !first && (found || cur == to);
99  first = false;
100  });
101  return found;
102  }
103 
104  /** Obtains the set of all vertices in the same clique than the given vertex */
105  const std::set<Vertex, Compare> clique(const Vertex& vertex) const {
106  std::set<Vertex, Compare> res;
107  res.insert(vertex);
108  for (const auto& cur : vertices()) {
109  if (reaches(vertex, cur) && reaches(cur, vertex)) {
110  res.insert(cur);
111  }
112  }
113  return res;
114  }
115 
116  /** A generic utility for depth-first visits */
117  template <typename Lambda>
118  void visitDepthFirst(const Vertex& vertex, const Lambda& lambda) const {
119  std::set<Vertex, Compare> visited;
120  visitDepthFirst(vertex, lambda, visited);
121  }
122 
123  /** Enables graphs to be printed (e.g. for debugging) */
124  void print(std::ostream& out) const {
125  bool first = true;
126  out << "{";
127  for (const auto& cur : _successors) {
128  for (const auto& trg : cur.second) {
129  if (!first) {
130  out << ",";
131  }
132  out << cur.first << "->" << trg;
133  first = false;
134  }
135  }
136  out << "}";
137  }
138 
139  friend std::ostream& operator<<(std::ostream& out, const Graph& g) {
140  g.print(out);
141  return out;
142  }
143 
144 private:
145  // not a very efficient but simple graph representation
146  std::set<Vertex, Compare> _vertices; // all the vertices in the graph
147  std::map<Vertex, std::set<Vertex, Compare>> _successors; // all edges forward directed
148  std::map<Vertex, std::set<Vertex, Compare>> _predecessors; // all edges backward
149 
150  /** The internal implementation of depth-first visits */
151  template <typename Lambda>
152  void visitDepthFirst(
153  const Vertex& vertex, const Lambda& lambda, std::set<Vertex, Compare>& visited) const {
154  lambda(vertex);
155  auto pos = _successors.find(vertex);
156  if (pos == _successors.end()) {
157  return;
158  }
159  for (const auto& cur : pos->second) {
160  if (visited.insert(cur).second) {
161  visitDepthFirst(cur, lambda, visited);
162  }
163  }
164  }
165 };
166 
167 inline std::string toBase64(const std::string& data) {
168  static const std::vector<char> table = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
169  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
170  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y',
171  'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'};
172  std::string result;
173  std::string tmp = data;
174  unsigned int padding = 0;
175  if (data.size() % 3 == 2) {
176  padding = 1;
177  } else if (data.size() % 3 == 1) {
178  padding = 2;
179  }
180 
181  for (unsigned int i = 0; i < padding; i++) {
182  tmp.push_back(0);
183  }
184  for (unsigned int i = 0; i < tmp.size(); i += 3) {
185  auto c1 = static_cast<unsigned char>(tmp[i]);
186  auto c2 = static_cast<unsigned char>(tmp[i + 1]);
187  auto c3 = static_cast<unsigned char>(tmp[i + 2]);
188  unsigned char index1 = c1 >> 2;
189  unsigned char index2 = ((c1 & 0x03) << 4) | (c2 >> 4);
190  unsigned char index3 = ((c2 & 0x0F) << 2) | (c3 >> 6);
191  unsigned char index4 = c3 & 0x3F;
192 
193  result.push_back(table[index1]);
194  result.push_back(table[index2]);
195  result.push_back(table[index3]);
196  result.push_back(table[index4]);
197  }
198  if (padding == 1) {
199  result[result.size() - 1] = '=';
200  } else if (padding == 2) {
201  result[result.size() - 1] = '=';
202  result[result.size() - 2] = '=';
203  }
204  return result;
205 }
206 
207 inline std::string convertDotToSVG(const std::string& dotSpec) {
208  // Check if dot is present
209  std::string cmd = which("dot");
210  if (!isExecutable(cmd)) {
211  return "";
212  }
213 
214  TempFileStream dotFile;
215  dotFile << dotSpec;
216  dotFile.flush();
217  return execStdOut("dot -Tsvg < " + dotFile.getFileName()).str();
218 }
219 
220 inline void printHTMLGraph(std::ostream& out, const std::string& dotSpec, const std::string& id) {
221  std::string data = convertDotToSVG(dotSpec);
222 
223  if (data.find("<svg") != std::string::npos) {
224  out << "<img alt='graph image' src='data:image/svg+xml;base64," << toBase64(data) << "'><br/>\n";
225  } else {
226  out << "<div class='" << id << "-source"
227  << "'>\n<pre>" << dotSpec << "</pre>\n";
228  out << "</div>\n";
229  }
230 }
231 
232 } // end of namespace souffle
souffle::execStdOut
std::stringstream execStdOut(char const *cmd)
Definition: FileUtil.h:274
souffle::Graph::insert
void insert(const Vertex &from, const Vertex &to)
Adds a new edge from the given vertex to the target vertex.
Definition: GraphUtils.h:51
souffle::Graph::visitDepthFirst
void visitDepthFirst(const Vertex &vertex, const Lambda &lambda) const
A generic utility for depth-first visits.
Definition: GraphUtils.h:130
souffle::toBase64
std::string toBase64(const std::string &data)
Definition: GraphUtils.h:173
souffle::Graph::successors
const std::set< Vertex, Compare > & successors(const Vertex &from) const
Returns the set of vertices the given vertex has edges to.
Definition: GraphUtils.h:75
souffle::Graph::print
void print(std::ostream &out) const
Enables graphs to be printed (e.g.
Definition: GraphUtils.h:136
souffle::TempFileStream::getFileName
std::string const & getFileName() const
Definition: FileUtil.h:303
souffle::TempFileStream
Definition: FileUtil.h:292
souffle::printHTMLGraph
void printHTMLGraph(std::ostream &out, const std::string &dotSpec, const std::string &id)
Definition: GraphUtils.h:226
souffle::Graph::_successors
std::map< Vertex, std::set< Vertex, Compare > > _successors
Definition: GraphUtils.h:159
i
size_t i
Definition: json11.h:663
souffle::Graph
A simple graph structure for graph-based operations.
Definition: GraphUtils.h:40
souffle::Graph::predecessors
const std::set< Vertex, Compare > & predecessors(const Vertex &to) const
Returns the set of vertices the given vertex has edges from.
Definition: GraphUtils.h:80
souffle::isExecutable
bool isExecutable(const std::string &name)
Check whether a given file exists and it is an executable.
Definition: FileUtil.h:97
souffle::which
std::string which(const std::string &name)
Simple implementation of a which tool.
Definition: FileUtil.h:104
souffle::Graph::_predecessors
std::map< Vertex, std::set< Vertex, Compare > > _predecessors
Definition: GraphUtils.h:160
souffle::convertDotToSVG
std::string convertDotToSVG(const std::string &dotSpec)
Definition: GraphUtils.h:213
souffle::Graph::operator<<
friend std::ostream & operator<<(std::ostream &out, const Graph &g)
Definition: GraphUtils.h:151
souffle::Graph::contains
bool contains(const Vertex &from, const Vertex &to) const
Determines whether the given edge is present.
Definition: GraphUtils.h:90
souffle::Graph::clique
const std::set< Vertex, Compare > clique(const Vertex &vertex) const
Obtains the set of all vertices in the same clique than the given vertex.
Definition: GraphUtils.h:117
souffle::Graph::reaches
bool reaches(const Vertex &from, const Vertex &to) const
Determines whether there is a directed path between the two vertices.
Definition: GraphUtils.h:100
FileUtil.h
souffle
Definition: AggregateOp.h:25
TCB_SPAN_NAMESPACE_NAME::detail::data
constexpr auto data(C &c) -> decltype(c.data())
Definition: span.h:210
souffle::Graph::_vertices
std::set< Vertex, Compare > _vertices
Definition: GraphUtils.h:158
souffle::Graph::vertices
const std::set< Vertex, Compare > & vertices() const
Obtains a reference to the set of all vertices.
Definition: GraphUtils.h:70
souffle::Graph::contains
bool contains(const Vertex &vertex) const
Determines whether the given vertex is present.
Definition: GraphUtils.h:85