ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
CircuitFromMMap.cpp
Go to the documentation of this file.
1/**
2 * @file CircuitFromMMap.cpp
3 * @brief Build in-memory circuits from the mmap-backed store.
4 *
5 * Implements the free functions declared in @c CircuitFromMMap.h:
6 * - @c getBooleanCircuit(): reads the mmap store (via the background
7 * worker IPC channel) and constructs a @c BooleanCircuit.
8 * - @c getGenericCircuit(): same but constructs a @c GenericCircuit.
9 *
10 * The internal @c getCircuitFromMMap<C>() template handles the IPC
11 * protocol: it sends a request through the shared-memory pipe,
12 * receives a Boost-serialised circuit blob from the background worker,
13 * and deserialises it into the appropriate circuit type.
14 */
15#include <cmath>
16
17#include <boost/archive/binary_iarchive.hpp>
18#include <boost/iostreams/device/array.hpp>
19#include <boost/iostreams/stream.hpp>
20
21#include "CircuitFromMMap.h"
22#include "MMappedCircuit.h"
23#include "HybridEvaluator.h"
24#include "RangeCheck.h"
25#include "having_semantics.hpp"
26#include "semiring/BoolExpr.h"
27#include "provsql_utils_cpp.h"
28
29#include <vector>
30
31extern "C" {
32#include "miscadmin.h"
33#include "provsql_shmem.h"
34#include "provsql_mmap.h"
35#include "provsql_utils.h"
36}
37
38/**
39 * @brief Read and deserialise a circuit rooted at @p token from the mmap worker.
40 * @tparam C Circuit type to deserialise (@c BooleanCircuit or @c GenericCircuit).
41 * @param token UUID of the root gate to retrieve.
42 * @param message_char IPC message-type byte sent to the background worker.
43 * @return Deserialised circuit of type @c C.
44 */
45template<typename C>
46static C getCircuitFromMMap(pg_uuid_t token, char message_char)
47{
49 ADDWRITEM(&message_char, char);
50 ADDWRITEM(&MyDatabaseId, Oid);
51 ADDWRITEM(&token, pg_uuid_t);
52
54 if(!SENDWRITEM())
55 provsql_error("Cannot write to pipe (message type %c)", message_char);
56
57 unsigned long size;
58 if(!READB(size, unsigned long))
59 provsql_error("Cannot read from pipe (message type %c)", message_char);
60
61 char *buf = new char[size];
62 if(!READB_BYTES(buf, size)) {
64 delete [] buf;
65 provsql_error("Cannot read from pipe (message type %c)", message_char);
66 }
68
69 boost::iostreams::stream<boost::iostreams::array_source> stream(buf, size);
70 boost::archive::binary_iarchive ia(stream);
71 C c;
72 ia >> c;
73
74 delete [] buf;
75
76 return c;
77}
78
81 pg_uuid_t token,
82 gate_t &gate,
83 std::unordered_map<gate_t, gate_t> &gc_to_bc)
84{
85 auto ggate = gc.getGate(uuid2string(token));
87 for(gate_t u: gc.getInputs()) {
88 gc_to_bc[u]=c.setGate(gc.getUUID(u), BooleanGate::IN, gc.getProb(u));
89 }
90 for(size_t i=0; i<gc.getNbGates(); ++i) {
91 auto u=static_cast<gate_t>(i);
92 if(gc.getGateType(u)==gate_mulinput) {
93 gc_to_bc[u]=c.setGate(gc.getUUID(u), BooleanGate::MULIN, gc.getProb(u));
94 c.setInfo(gc_to_bc[u], gc.getInfos(u).first);
95 c.addWire(
96 gc_to_bc[u],
97 gc_to_bc[gc.getWires(u)[0]]);
98 }
99 }
101 provsql_having(gc, ggate, gc_to_bc, semiring);
102 gate=gc.evaluate(ggate, gc_to_bc, semiring);
103 propagateDNNFCertificate(gc, gc_to_bc, c);
104
105 return c;
106}
107
109 const GenericCircuit &gc,
110 const std::unordered_map<gate_t, gate_t> &gc_to_bc,
112{
113 for(const auto &[u, b]: gc_to_bc) {
114 const auto t = gc.getGateType(u);
115 if((t != gate_plus && t != gate_times) ||
116 gc.getInfos(u).first != DNNF_CERT_INFO)
117 continue;
118 const auto bt = c.getGateType(b);
119 if((t == gate_plus && bt == BooleanGate::OR) ||
120 (t == gate_times && bt == BooleanGate::AND))
122 }
123}
124
126{
128 std::unordered_map<gate_t, gate_t> gc_to_bc;
129 return getBooleanCircuit(gc, token, gate, gc_to_bc);
130}
131
132/**
133 * @brief Apply the universal load-time simplification passes to @p gc.
134 *
135 * Extracted from @c getGenericCircuit so the joint-circuit loader
136 * (@c getJointCircuit) runs the same passes on its multi-root output.
137 * Gated by the @c provsql.simplify_on_load GUC, identical semantics.
138 */
140{
143 /* Fold deterministic @c gate_arith subtrees to @c gate_value
144 * before @c foldSemiringIdentities (which then collapses any
145 * single-wire @c gate_times / @c gate_plus wrappers around the
146 * resulting @c gate_value). Constant folding is uniformly safe
147 * across consumers: a @c gate_value carries no random identity,
148 * so no shared-RV coupling is decoupled by the rewrite. Lifts
149 * common parser shapes -- the @c -c::random_variable cast emits
150 * @c arith(NEG, value:c) where @c value:-c would round-trip
151 * identically -- into the canonical form so downstream
152 * @c collectRvConstraints / @c asRvVsConstCmp recognise them. */
155 }
156 /* Class-gated simplification, independent of simplify_on_load
157 * (dropping the universal passes does not drop these). Under the
158 * 'boolean' provenance class the full rule set applies
159 * (times-idempotence and times-absorbs-plus included); under
160 * 'absorptive', only the rules sound in every absorptive semiring
161 * (plus-idempotence, plus-with-one absorber, plus-absorbs-times).
162 * Each rule application marks the gate in the matching in-memory
163 * side-band set, the load-time signal to the evaluator that
164 * semirings outside the rule's class must refuse. */
169 }
170}
171
173{
174#ifdef PROVSQL_INPROCESS_STORE
175 GenericCircuit gc = provsql_inproc_generic_circuit(token);
176#else
178#endif
179
180 /* Apply universal cmp-resolution passes (currently RangeCheck) at
181 * load time so every downstream consumer -- semiring evaluators,
182 * MC, view_circuit, PROV export -- sees the simplified circuit.
183 * Each pass replaces decided gate_cmps with Bernoulli gate_input
184 * gates with probability 0 or 1 via
185 * GenericCircuit::resolveCmpToBernoulli; the rewrite is uniform
186 * across semirings (gate_zero / gate_one are the additive /
187 * multiplicative identities in any semiring) so a single sweep
188 * here is correct for every later evaluator.
189 *
190 * Gated by the provsql.simplify_on_load GUC so users debugging
191 * raw circuit structure can opt out. */
193
194 return gc;
195}
196
197/**
198 * @brief IPC: ship a 'j' (joint) request to the mmap worker and
199 * deserialise the returned @c GenericCircuit.
200 *
201 * Mirrors @c getCircuitFromMMap but writes the multi-root payload
202 * the worker's @c 'j' handler expects: <tt>'j' Oid nb_roots {pg_uuid_t}*</tt>.
203 * The response shape is identical to @c 'g' -- @c unsigned @c long
204 * size prefix followed by a Boost-serialised @c GenericCircuit.
205 */
207 pg_uuid_t root_token, pg_uuid_t event_token)
208{
209#ifdef PROVSQL_INPROCESS_STORE
210 return provsql_inproc_joint_circuit(root_token, event_token);
211#else
212 char message_char = 'j';
213 unsigned nb_roots = 2;
214 STARTWRITEM();
215 ADDWRITEM(&message_char, char);
216 ADDWRITEM(&MyDatabaseId, Oid);
217 ADDWRITEM(&nb_roots, unsigned);
218 ADDWRITEM(&root_token, pg_uuid_t);
219 ADDWRITEM(&event_token, pg_uuid_t);
220
222 if(!SENDWRITEM())
223 provsql_error("Cannot write to pipe (message type j)");
224
225 unsigned long size;
226 if(!READB(size, unsigned long))
227 provsql_error("Cannot read from pipe (message type j)");
228
229 char *buf = new char[size];
230 if(!READB_BYTES(buf, size)) {
232 delete [] buf;
233 provsql_error("Cannot read from pipe (message type j)");
234 }
236
237 boost::iostreams::stream<boost::iostreams::array_source> stream(buf, size);
238 boost::archive::binary_iarchive ia(stream);
240 ia >> c;
241
242 delete [] buf;
243
244 return c;
245#endif /* PROVSQL_INPROCESS_STORE */
246}
247
249 pg_uuid_t root_token,
250 pg_uuid_t event_token,
251 gate_t &root_gate,
252 gate_t &event_gate)
253{
254 GenericCircuit gc = getJointCircuitFromMMap(root_token, event_token);
255
257
258 /* Resolve the gate_t for the two roots AFTER simplification. The
259 * passes mutate gate types in place but never delete gates, so the
260 * UUID-to-gate_t map (and therefore @c getGate) stays valid. */
261 root_gate = gc.getGate(uuid2string(root_token));
262 event_gate = gc.getGate(uuid2string(event_token));
263
264 return gc;
265}
Boolean-expression (lineage formula) semiring.
constexpr unsigned DNNF_CERT_INFO
d-DNNF certificate value for the (gate-type-specific) per-gate info field.
@ OR
Logical disjunction of child gates.
@ AND
Logical conjunction of child gates.
@ IN
Input (variable) gate representing a base tuple.
@ MULIN
Multivalued-input gate (one of several options).
static GenericCircuit getJointCircuitFromMMap(pg_uuid_t root_token, pg_uuid_t event_token)
IPC: ship a 'j' (joint) request to the mmap worker and deserialise the returned GenericCircuit.
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.
void propagateDNNFCertificate(const GenericCircuit &gc, const std::unordered_map< gate_t, gate_t > &gc_to_bc, BooleanCircuit &c)
Propagate the per-gate d-DNNF certificate from gc to c.
GenericCircuit getJointCircuit(pg_uuid_t root_token, pg_uuid_t event_token, gate_t &root_gate, gate_t &event_gate)
Build a GenericCircuit containing the closures of two roots, with shared subgraphs unified.
static C getCircuitFromMMap(pg_uuid_t token, char message_char)
Read and deserialise a circuit rooted at token from the mmap worker.
GenericCircuit getGenericCircuit(pg_uuid_t token)
Build a GenericCircuit from the mmap store rooted at token.
static void applyLoadTimeSimplification(GenericCircuit &gc)
Apply the universal load-time simplification passes to gc.
Build in-memory circuits from the mmap-backed persistent store.
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:49
Peephole simplifier for continuous gate_arith sub-circuits.
Persistent, mmap-backed storage for the full provenance circuit.
Support-based bound check for continuous-RV comparators.
Boolean circuit for provenance formula evaluation.
gate_t setGate(BooleanGate type) override
Allocate a new gate with type type and no UUID.
void setInfo(gate_t g, unsigned info)
Store an integer annotation on gate g.
std::vector< gate_t > & getWires(gate_t g)
Return a mutable reference to the child-wire list of gate g.
Definition Circuit.h:140
gateType getGateType(gate_t g) const
Return the type of gate g.
Definition Circuit.h:130
void addWire(gate_t f, gate_t t)
Add a directed wire from gate f (parent) to gate t (child).
Definition Circuit.hpp:81
uuid getUUID(gate_t g) const
Return the UUID string associated with gate g.
Definition Circuit.hpp:46
gate_t getGate(const uuid &u)
Return (or create) the gate associated with UUID u.
Definition Circuit.hpp:33
std::vector< gate_t >::size_type getNbGates() const
Return the total number of gates in the circuit.
Definition Circuit.h:103
In-memory provenance circuit with semiring-generic evaluation.
S::value_type evaluate(gate_t g, std::unordered_map< gate_t, typename S::value_type > &provenance_mapping, S semiring) const
Evaluate the sub-circuit rooted at gate g over semiring semiring.
bool foldSemiringIdentities()
Drop semiring identity wires and collapse single-wire gate_times / gate_plus to their lone non-identi...
void foldAbsorptiveIdentities()
Absorptive-rules-only variant of foldBooleanIdentities(): the joint fixpoint of the absorptive fold r...
double getProb(gate_t g) const
Return the probability for gate g.
const std::set< gate_t > & getInputs() const
Return the set of input (leaf) gates.
std::pair< unsigned, unsigned > getInfos(gate_t g) const
Return the integer annotation pair for gate g.
void foldBooleanIdentities()
Apply the Boolean-only AND the absorptive simplification rules to gate_plus and gate_times,...
Provenance-as-Boolean-circuit semiring.
Definition BoolExpr.h:48
Provenance evaluation helper for HAVING-clause circuits.
void provsql_having(GenericCircuit &c, gate_t g, MapT &mapping, SemiringT S=SemiringT{})
Rewrite HAVING comparison gates in the circuit by enumerating possible worlds.
unsigned runConstantFold(GenericCircuit &gc)
Constant-fold pass over every gate_arith in gc.
unsigned runRangeCheck(GenericCircuit &gc)
Run the support-based pruning pass over gc.
bool provsql_absorptive_provenance
Derived flag: the session's provenance class is 'absorptive' or 'boolean' – licenses constructions so...
Definition provsql.c:108
bool provsql_simplify_on_load
Run universal cmp-resolution passes when getGenericCircuit returns; controlled by the provsql....
Definition provsql.c:103
bool provsql_boolean_provenance
Derived flag: the session's provenance class is 'boolean' – enables the Boolean-only machinery (safe-...
Definition provsql.c:107
#define provsql_error(fmt,...)
Report a fatal ProvSQL error and abort the current transaction.
Background worker and IPC primitives for mmap-backed circuit storage.
#define READB_BYTES(ptr, n)
Read exactly n bytes of a reply from the main-to-background pipe.
#define READB(var, type)
Read one value of type from the main-to-background pipe.
#define STARTWRITEM()
Reset the shared write buffer for a new batched write.
#define ADDWRITEM(pvar, type)
Append one value of type to the shared write buffer.
#define SENDWRITEM()
Flush the shared write buffer to the background-to-main pipe atomically.
void provsql_shmem_unlock(void)
Release the ProvSQL LWLock.
void provsql_shmem_lock_exclusive(void)
Acquire the ProvSQL LWLock in exclusive mode.
Shared-memory segment and inter-process pipe management.
Core types, constants, and utilities shared across ProvSQL.
string uuid2string(pg_uuid_t uuid)
Format a pg_uuid_t as a std::string.
C++ utility functions for UUID manipulation.
UUID structure.