ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
DotCircuit.cpp
Go to the documentation of this file.
1/**
2 * @file DotCircuit.cpp
3 * @brief DotCircuit method implementations and GraphViz rendering.
4 *
5 * Implements:
6 * - @c DotCircuit::addGate(): allocate a gate and extend the @c desc vector.
7 * - @c DotCircuit::setGate(const uuid&, DotGate): create a gate by UUID.
8 * - @c DotCircuit::setGate(const uuid&, DotGate, std::string): create a gate
9 * with a label string stored in @c desc.
10 * - @c DotCircuit::toString(): return the description string for a gate.
11 * - @c DotCircuit::render(): produce a complete GraphViz @c digraph string
12 * with semiring symbols (⊗, ⊕, ⊖, δ) as node labels and the
13 * provenance token UUIDs as edge labels for input gates.
14 */
15#include "DotCircuit.h"
16#include "external_tool.h"
17#include "ToolRegistry.h"
18#include "scoped_tempdir.h"
19#include <type_traits>
20
21extern "C"
22{
23#include "provsql_utils.h"
24#include <unistd.h>
25}
26
27#include <cassert>
28#include <string>
29#include <fstream>
30#include <sstream>
31#include <cstdlib>
32
33// Has to be redefined because of name hiding
35{
36 auto id = Circuit::setGate(u, type);
37 if(type == DotGate::IN)
38 inputs.insert(id);
39 return id;
40}
41
42gate_t DotCircuit::setGate(const uuid &u, DotGate type, std::string d)
43{
44 auto id = setGate(u, type);
45 desc[static_cast<std::underlying_type<gate_t>::type>(id)] = d;
46 return id;
47}
48
50{
51 auto id=Circuit::addGate();
52 desc.push_back("");
53 return id;
54}
55
56//Outputs the gate in Graphviz dot format
57std::string DotCircuit::toString(gate_t) const
58{
59 std::string op;
60 std::string result="digraph circuit{\n graph [rankdir=UD] ;\n";
61
62 //looping through the gates
63 //eliminating the minusr and minusl gates
64 unsigned i = 0;
65 for (auto g : gates)
66 {
67 if (g != DotGate::OMINUSR && g != DotGate::OMINUSL)
68 {
69 result += std::to_string(i) + " [label=";
70 switch (g)
71 {
72 case DotGate::IN:
73 result += "\"" + desc[i] + "\"";
74 break;
75 case DotGate::OMINUS:
76 result += "\"⊖\"";
77 break;
79 result += "\"?\"";
80 break;
81 case DotGate::OTIMES:
82 result += "\"⊗\"";
83 break;
84 case DotGate::OPLUS:
85 result += "\"⊕\"";
86 break;
87 case DotGate::DELTA:
88 result += "\"δ\"";
89 break;
90 case DotGate::EQ:
91 result += "\"" + desc[i] + "\"";
92 break;
94 result += "\"Π" + desc[i] + "\"";
95 break;
98 break;
99 }
100 if(i==0)
101 result+=",shape=\"double\"";
102 result+="];\n";
103 }
104 i++;
105 }
106
107 //looping through the gates and their wires
108 for(i=0; i<wires.size(); ++i) {
109 if(gates[i] != DotGate::OMINUSR && gates[i] != DotGate::OMINUSL) {
110 std::unordered_map<gate_t, unsigned> number_gates;
111 for(auto s: wires[i]) {
112 if(number_gates.find(s)!=number_gates.end()) {
113 number_gates[s] = number_gates[s]+1;
114 }
115 else
116 {
117 number_gates[s] = 1;
118 }
119 }
120 for(auto [s,n]: number_gates)
121 {
123 for(auto t: getWires(s)) {
124 result += std::to_string(i)+" -> "+to_string(t);
126 result += " [label=\"R\"];\n";
127 else
128 result += " [label=\"L\"];\n";
129 }
130 }
131 else {
132 result += std::to_string(i)+" -> "+to_string(s);
133 if(n==1) {
134 result += ";\n";
135 }
136 else
137 {
138 result += " [label=\"" + std::to_string(n) + "\"];\n";
139 }
140 }
141 }
142 }
143 }
144 return result + "}";
145}
146
147std::string DotCircuit::render() const {
148 //Executing the Graphviz dot renderer through graph-easy for ASCII
149 //output. The executable and its enabled flag come from the tool
150 //registry (logical name "graph-easy"); a record absent from the
151 //registry resolves to itself.
152 std::string render_bin = "graph-easy";
153 std::string render_argtpl = "--as=boxart --output={out} {in}";
154 {
155 const provsql::ToolRecord *rec = provsql::tool_registry().find("graph-easy");
156 if(rec != nullptr) {
157 if(!rec->enabled)
158 throw CircuitException(
159 "Tool 'graph-easy' is disabled in the tool registry");
160 render_bin = rec->binary;
161 render_argtpl = rec->argtpl;
162 }
163 }
164 if(find_external_tool(render_bin).empty()) {
165 throw CircuitException(
166 render_bin + " not found on PATH; install it or add its "
167 "directory to provsql.tool_search_path");
168 }
169
170 // Private 0700 directory rather than a bare mkstemp file so the
171 // deterministically-derived sibling output path (.out) cannot be
172 // raced by a local user pre-creating a symlink before graph-easy
173 // opens it. The RAII guard unlinks both files and rmdirs at scope
174 // exit even when the body throws.
176 std::string filename = tmp.file("dot");
177 std::string outfilename = tmp.file("dot.out");
178
179 {
180 std::ofstream ofs(filename);
181 ofs << toString(gate_t{0});
182 }
183
184 std::string cmdline=provsql::expandCommandTemplate(
185 render_argtpl, render_bin, filename, outfilename);
186
187 int retvalue = run_external_tool(cmdline);
188 if(retvalue)
189 throw CircuitException(format_external_tool_status(retvalue, "graph-easy"));
190
191 std::ifstream ifs(outfilename.c_str());
192 std::string str((std::istreambuf_iterator<char>(ifs)),
193 std::istreambuf_iterator<char>());
194
195 if(provsql_verbose>=20)
196 tmp.keep();
197
198 return str;
199}
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:49
std::string to_string(gate_t g)
Convert a gate_t to its decimal string representation.
Definition Circuit.h:250
Provenance circuit variant that renders to GraphViz DOT format.
DotGate
Gate types for a DOT visualisation circuit.
Definition DotCircuit.h:42
@ PROJECT
Projection gate.
Definition DotCircuit.h:49
@ OPLUS
Semiring plus (⊕).
Definition DotCircuit.h:45
@ EQ
Equijoin gate.
Definition DotCircuit.h:50
@ OMINUS
Semiring monus (⊖), full.
Definition DotCircuit.h:46
@ OMINUSL
Monus, left child only.
Definition DotCircuit.h:48
@ OMINUSR
Monus, right child only.
Definition DotCircuit.h:47
@ DELTA
δ-semiring operator
Definition DotCircuit.h:52
@ IN
Input (variable) gate.
Definition DotCircuit.h:51
@ UNDETERMINED
Placeholder gate not yet assigned a type.
Definition DotCircuit.h:43
@ OTIMES
Semiring times (⊗).
Definition DotCircuit.h:44
In-memory catalog of the external tools ProvSQL can invoke.
Exception type thrown by circuit operations on invalid input.
Definition Circuit.h:206
std::string uuid
Definition Circuit.h:65
std::vector< gate_t > & getWires(gate_t g)
Definition Circuit.h:140
DotGate getGateType(gate_t g) const
Definition Circuit.h:130
virtual gate_t setGate(const uuid &u, gateType type)
Create or update the gate associated with UUID u.
Definition Circuit.hpp:73
std::vector< DotGate > gates
Definition Circuit.h:71
std::vector< std::vector< gate_t > > wires
Definition Circuit.h:72
virtual gate_t addGate()
Allocate a new gate with a default-initialised type.
Definition Circuit.hpp:56
virtual std::string toString(gate_t g) const override
Return a textual description of gate g for debugging.
gate_t addGate() override
Allocate a new gate with a default-initialised type.
std::set< gate_t > inputs
Input gate IDs (rendered as leaf nodes).
Definition DotCircuit.h:63
gate_t setGate(const uuid &u, DotGate type) override
Create or update the gate associated with UUID u.
std::string render() const
Render the entire circuit as a GraphViz DOT digraph string.
std::vector< std::string > desc
Per-gate label strings (indexed by gate ID).
Definition DotCircuit.h:64
RAII guard around a freshly mkdtemp'd /tmp directory.
std::string file(const std::string &basename)
Build a path under the temp dir and register it for cleanup.
void keep()
Leave the directory on disk; cleanup is skipped at scope exit.
const ToolRecord * find(const std::string &name) const
Find a record by logical name, or nullptr if none is registered.
int run_external_tool(const std::string &cmdline)
Run a shell command line in its own process group, optionally extending PATH, interruptible by query ...
std::string format_external_tool_status(int rv, const std::string &tool)
Decode a system() return value into a human-readable message.
std::string find_external_tool(const std::string &name)
Locate an external tool by name.
Helpers for invoking external command-line tools.
ToolRegistry & tool_registry()
Shorthand for ToolRegistry::instance().
std::string expandCommandTemplate(const std::string &tpl, const std::string &binary, const std::string &in, const std::string &out, const std::vector< std::pair< std::string, std::string > > &extra={})
Expand a command template into a runnable shell command line.
int provsql_verbose
Verbosity level; controlled by the provsql.verbose_level GUC.
Definition provsql.c:89
Core types, constants, and utilities shared across ProvSQL.
One registered external tool.