ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
ToolRegistry.cpp
Go to the documentation of this file.
1/**
2 * @file ToolRegistry.cpp
3 * @brief Seed and mutation logic for the external-tool registry.
4 *
5 * The seed mirrors exactly the tools ProvSQL has always known about, with
6 * their default executable names and a preference order that keeps the
7 * historical selection (@c d4 first among compilers, matching the
8 * @c provsql.fallback_compiler default). See @ref ToolRegistry.h.
9 */
10#include "ToolRegistry.h"
11
12#include <algorithm>
13
14namespace provsql {
15
16bool ToolRecord::hasOperation(const std::string &op) const
17{
18 return std::find(operations.begin(), operations.end(), op)
19 != operations.end();
20}
21
22bool ToolRecord::acceptsInput(const std::string &fmt) const
23{
24 return std::find(input_formats.begin(), input_formats.end(), fmt)
25 != input_formats.end();
26}
27
29 const std::string &in, const std::string &out,
30 const std::string &binary_override,
31 const std::vector<std::pair<std::string, std::string>> &extra) const
32{
33 return expandCommandTemplate(argtpl, binary_override, in, out, extra);
34}
35
37{
38 records_.clear();
39
40 // Fields: name, kind, binary, operations, input_formats, output_format,
41 // parser, preference, enabled, dependencies, argtpl.
42 // operations / input_formats / output_format use the KCMCP shared-registry
43 // names so CLI and (future) kcmcp-server records are comparable; `parser`
44 // is the CLI-only "how to decode this tool's raw output" tag (a kcmcp
45 // server returns output_format directly, so its records leave parser "").
46 //
47 // Knowledge compilers reading a Tseytin DIMACS CNF and emitting a d-DNNF.
48 // The single tolerant `nnf` parser auto-detects the c2d/d4 magic header,
49 // so it reads both the d4-family (header-less) and classic forms.
50 // Preference reproduces the historical "d4 is the default" bias.
51 records_.push_back({"d4", "cli", "d4", {"compile"}, {"dimacs-cnf"},
52 "ddnnf-nnf", "nnf", 100, true, {}, "-dDNNF {in} -out={out}"});
53 // d4v2 also accepts a BC-S1.2 circuit (native, structure-preserving): it is
54 // listed first so the dispatcher prefers it, falling back to dimacs-cnf.
55 // argtpl is the CNF command; argtpl_circuit the native-circuit one (`-t
56 // pcnf` projects gate variables out so the d-DNNF branches only on inputs).
57 records_.push_back({"d4v2", "cli", "d4v2", {"compile"},
58 {"circuit-bcs12", "dimacs-cnf"},
59 "ddnnf-nnf", "nnf", 90, true, {}, "-i {in} --dump-file {out}",
60 "-i {in} --input-type circuit -t pcnf --dump-file {out}"});
61 records_.push_back({"c2d", "cli", "c2d", {"compile"}, {"dimacs-cnf"},
62 "ddnnf-nnf", "nnf", 80, true, {}, "-in {in} -silent"});
63 records_.push_back({"minic2d", "cli", "minic2d", {"compile"}, {"dimacs-cnf"},
64 "ddnnf-nnf", "nnf", 70, true, {}, "-c {in}"});
65 records_.push_back({"dsharp", "cli", "dsharp", {"compile"}, {"dimacs-cnf"},
66 "ddnnf-nnf", "nnf", 60, true, {}, "-q -Fnnf {out} {in}"});
67
68 // Panini (KCBox): one binary, three logical variants selected by the
69 // --lang argument baked into each template. Its compiled form is its own
70 // DD format (no KCMCP code), so output_format/parser are the local
71 // "panini-dd"; paniniCompile() reads it.
72 records_.push_back({"panini-obdd", "cli", "panini", {"compile"}, {"dimacs-cnf"},
73 "panini-dd", "panini-dd", 52, true, {},
74 "Panini --lang \"OBDD\" --out {out} --quiet {in}"});
75 records_.push_back({"panini-obdd-and", "cli", "panini", {"compile"}, {"dimacs-cnf"},
76 "panini-dd", "panini-dd", 51, true, {},
77 "Panini --lang \"OBDD[AND]\" --out {out} --quiet {in}"});
78 records_.push_back({"panini-decdnnf", "cli", "panini", {"compile"}, {"dimacs-cnf"},
79 "panini-dd", "panini-dd", 50, true, {},
80 "Panini --lang \"Decision-DNNF\" --out {out} --quiet {in}"});
81
82 // Weighted model counters: read a (weighted) DIMACS CNF and return a number
83 // (KCMCP output_format "decimal"). sharpsat-td needs the flow_cutter_pace17
84 // helper (invoked by relative path, hence the cd) and a scratch {tmpdir};
85 // dpmc is a two-binary pipeline (htb | dmc) with no single binary of its
86 // own. The `wmc-line` parser scrapes the "c s exact" line; weightmc's
87 // mantissa x 2^e output needs its own `weightmc` parser.
88 records_.push_back({"sharpsat-td", "cli", "sharpsat-td", {"wmc"}, {"dimacs-cnf"},
89 "decimal", "wmc-line", 90, true, {"flow_cutter_pace17"},
90 "cd \"$(dirname \"$(command -v flow_cutter_pace17)\")\" && "
91 "{binary} -WE -decot 1 -decow 100 -tmpdir {tmpdir} "
92 "-cs 3500 -prec 20 {in} > {out} 2>&1"});
93 records_.push_back({"ganak", "cli", "ganak", {"wmc"}, {"dimacs-cnf"},
94 "decimal", "wmc-line", 80, true, {},
95 "--mode 7 {in} > {out} 2>&1"});
96 records_.push_back({"weightmc", "cli", "weightmc", {"wmc"}, {"dimacs-cnf"},
97 "decimal", "weightmc", 70, true, {},
98 "--startIteration=0 --gaussuntil=400 --verbosity=0 "
99 "--pivotAC={pivotAC} {in} > {out}"});
100 records_.push_back({"dpmc", "cli", "", {"wmc"}, {"dimacs-cnf"},
101 "decimal", "wmc-line", 60, true, {"htb", "dmc"},
102 "htb --cf={in} | dmc --cf={in} > {out} 2>&1"});
103
104 // Visualisation: a ProvSQL-local operation (no KCMCP counterpart); reads a
105 // GraphViz DOT and returns graph-easy's ASCII art verbatim.
106 records_.push_back({"graph-easy", "cli", "graph-easy", {"render"}, {"dot"},
107 "ascii", "ascii", 100, true, {},
108 "--as=boxart --output={out} {in}"});
109}
110
112{
113 seed();
114}
115
117{
118 static ToolRegistry registry;
119 return registry;
120}
121
122const ToolRecord *ToolRegistry::find(const std::string &name) const
123{
124 for (const auto &rec : records_)
125 if (rec.name == name)
126 return &rec;
127 return nullptr;
128}
129
130bool ToolRegistry::provides(const std::string &name, const std::string &op) const
131{
132 const ToolRecord *rec = find(name);
133 return rec != nullptr && rec->enabled && rec->hasOperation(op);
134}
135
136std::vector<const ToolRecord *>
137ToolRegistry::byOperation(const std::string &op) const
138{
139 std::vector<const ToolRecord *> out;
140 for (const auto &rec : records_)
141 if (rec.enabled && rec.hasOperation(op))
142 out.push_back(&rec);
143
144 std::sort(out.begin(), out.end(),
145 [](const ToolRecord *a, const ToolRecord *b) {
146 if (a->preference != b->preference)
147 return a->preference > b->preference;
148 return a->name < b->name;
149 });
150 return out;
151}
152
154{
155 for (auto &existing : records_) {
156 if (existing.name == rec.name) {
157 existing = rec;
158 return;
159 }
160 }
161 records_.push_back(rec);
162}
163
164bool ToolRegistry::remove(const std::string &name)
165{
166 auto it = std::find_if(records_.begin(), records_.end(),
167 [&](const ToolRecord &r) { return r.name == name; });
168 if (it == records_.end())
169 return false;
170 records_.erase(it);
171 return true;
172}
173
174bool ToolRegistry::setEnabled(const std::string &name, bool enabled)
175{
176 for (auto &rec : records_) {
177 if (rec.name == name) {
178 rec.enabled = enabled;
179 return true;
180 }
181 }
182 return false;
183}
184
185bool ToolRegistry::setPreference(const std::string &name, int preference)
186{
187 for (auto &rec : records_) {
188 if (rec.name == name) {
189 rec.preference = preference;
190 return true;
191 }
192 }
193 return false;
194}
195
196} // namespace provsql
In-memory catalog of the external tools ProvSQL can invoke.
std::vector< const ToolRecord * > byOperation(const std::string &op) const
Enabled tools advertising op, ordered by descending preference then name.
bool provides(const std::string &name, const std::string &op) const
True iff a record named name exists, is enabled, and advertises op.
std::vector< ToolRecord > records_
static ToolRegistry & instance()
Access the per-process registry, seeding it on first use.
void upsert(const ToolRecord &rec)
Register a new tool or replace the record with the same name.
bool setPreference(const std::string &name, int preference)
Set the preference of name; returns false if none existed.
void reset()
Discard all records and re-seed the compiled-in defaults.
bool setEnabled(const std::string &name, bool enabled)
Flip the enabled flag of name; returns false if none existed.
bool remove(const std::string &name)
Remove the record named name; returns false if none existed.
const ToolRecord * find(const std::string &name) const
Find a record by logical name, or nullptr if none is registered.
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.
One registered external tool.
bool acceptsInput(const std::string &fmt) const
bool hasOperation(const std::string &op) const
std::vector< std::string > input_formats
std::vector< std::string > operations
std::string buildCommand(const std::string &in, const std::string &out, const std::string &binary_override, const std::vector< std::pair< std::string, std::string > > &extra={}) const
Build the command line for this tool.