ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
tseytin_cnf.cpp
Go to the documentation of this file.
1/**
2 * @file tseytin_cnf.cpp
3 * @brief SQL function @c provsql.tseytin_cnf() – return the DIMACS CNF
4 * produced by the Tseytin transformation of a provenance circuit.
5 *
6 * This is the same encoding that @c BooleanCircuit::compilation() writes
7 * to a temp file before invoking @c d4 / @c c2d / @c minic2d / @c dsharp,
8 * but returned as a string so the user can inspect it or feed it to a
9 * standalone knowledge-compilation tool.
10 */
11extern "C" {
12#include "postgres.h"
13#include "fmgr.h"
14#if PG_VERSION_NUM >= 160000
15#include "varatt.h"
16#endif
17#include "catalog/pg_type.h"
18#include "utils/jsonb.h"
19#include "utils/fmgrprotos.h"
20#include "utils/uuid.h"
21#include "provsql_shmem.h"
22#include "provsql_utils.h"
23
24PG_FUNCTION_INFO_V1(tseytin_cnf);
25PG_FUNCTION_INFO_V1(tseytin_cnf_mapping_json);
26}
27
28#include "c_cpp_compatibility.h"
29#include "BooleanCircuit.h"
30#include "CircuitFromMMap.h"
31#include "provsql_utils_cpp.h"
32
33#include <sstream>
34#include <string>
35
36using namespace std;
37
38/**
39 * @brief PostgreSQL-callable entry point.
40 *
41 * Arguments: @c token (uuid), @c weighted (bool, default true),
42 * @c mapping (bool, default true).
43 * Returns: DIMACS CNF as text; when @c weighted, includes @c w lines;
44 * when @c mapping, prepends @c "c input <var> <uuid> <prob>" comments.
45 */
46Datum tseytin_cnf(PG_FUNCTION_ARGS)
47{
48 try {
49 if(PG_ARGISNULL(0))
50 PG_RETURN_NULL();
51 pg_uuid_t *token = DatumGetUUIDP(PG_GETARG_DATUM(0));
52
53 bool weighted = true;
54 if(!PG_ARGISNULL(1))
55 weighted = PG_GETARG_BOOL(1);
56
57 bool mapping = true;
58 if(!PG_ARGISNULL(2))
59 mapping = PG_GETARG_BOOL(2);
60
61 gate_t root;
62 BooleanCircuit c = getBooleanCircuit(*token, root);
64
65 string cnf = c.TseytinCNF(root, weighted, mapping);
66
67 text *result = (text *) palloc(VARHDRSZ + cnf.size());
68 SET_VARSIZE(result, VARHDRSZ + cnf.size());
69 memcpy((void *) VARDATA(result), cnf.c_str(), cnf.size());
70 PG_RETURN_TEXT_P(result);
71 } catch(const std::exception &e) {
72 provsql_error("%s", e.what());
73 } catch(...) {
74 provsql_error("Unknown exception");
75 }
76 PG_RETURN_NULL();
77}
78
79static void json_escape(std::ostringstream &out, const std::string &s)
80{
81 for(char ch : s) {
82 switch(ch) {
83 case '"': out << "\\\""; break;
84 case '\\': out << "\\\\"; break;
85 default: out << ch;
86 }
87 }
88}
89
90/**
91 * @brief PostgreSQL-callable entry point: variable mapping as jsonb.
92 *
93 * Argument: @c token (uuid). Returns a jsonb array of objects
94 * @c {"variable":int,"gate":uuid-string,"probability":float8}, one per
95 * input gate, with the same variable numbering as @c tseytin_cnf. The
96 * SQL wrapper @c tseytin_cnf_mapping unnests this into a table.
97 */
98Datum tseytin_cnf_mapping_json(PG_FUNCTION_ARGS)
99{
100 if(PG_ARGISNULL(0))
101 PG_RETURN_NULL();
102 pg_uuid_t *token = DatumGetUUIDP(PG_GETARG_DATUM(0));
103
104 std::ostringstream out;
105 out << '[';
106 try {
107 gate_t root;
108 BooleanCircuit c = getBooleanCircuit(*token, root);
110
111 bool first = true;
112 for(const auto &m : c.tseytinVariableMapping()) {
113 if(!first) out << ',';
114 first = false;
115 out << "{\"variable\":" << m.variable << ",\"gate\":";
116 if(m.uuid.empty()) {
117 out << "null";
118 } else {
119 out << '"';
120 json_escape(out, m.uuid);
121 out << '"';
122 }
123 out << ",\"probability\":";
124 if(m.probability != m.probability) /* NaN */
125 out << "null";
126 else
127 out << m.probability;
128 out << '}';
129 }
130 } catch(const std::exception &e) {
131 provsql_error("%s", e.what());
132 } catch(...) {
133 provsql_error("Unknown exception");
134 }
135 out << ']';
136
137 Datum json_datum = DirectFunctionCall1(
138 jsonb_in, CStringGetDatum(pstrdup(out.str().c_str())));
139 PG_RETURN_DATUM(json_datum);
140}
Boolean provenance circuit with support for knowledge compilation.
BooleanCircuit getBooleanCircuit(GenericCircuit &gc, pg_uuid_t token, gate_t &gate, std::unordered_map< gate_t, gate_t > &gc_to_bc)
Build a BooleanCircuit from an already-loaded GenericCircuit.
Build in-memory circuits from the mmap-backed persistent store.
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:49
Fix gettext macro conflicts between PostgreSQL and the C++ STL.
Boolean circuit for provenance formula evaluation.
std::vector< CNFInputMapping > tseytinVariableMapping() const
Map each input gate to its DIMACS variable, UUID, probability.
std::string TseytinCNF(gate_t g, bool display_prob, bool mapping=false) const
Return the Tseytin transformation of the sub-circuit at g as a DIMACS string.
void rewriteMultivaluedGates()
Rewrite all MULVAR/MULIN gate clusters into standard AND/OR/NOT circuits.
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
Shared-memory segment and inter-process pipe management.
Core types, constants, and utilities shared across ProvSQL.
C++ utility functions for UUID manipulation.
UUID structure.
Datum tseytin_cnf(PG_FUNCTION_ARGS)
PostgreSQL-callable entry point.
Datum tseytin_cnf_mapping_json(PG_FUNCTION_ARGS)
PostgreSQL-callable entry point: variable mapping as jsonb.
static void json_escape(std::ostringstream &out, const std::string &s)