ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
GenericCircuit.h
Go to the documentation of this file.
1/**
2 * @file GenericCircuit.h
3 * @brief Semiring-agnostic in-memory provenance circuit.
4 *
5 * @c GenericCircuit is an in-memory directed acyclic graph whose gate
6 * types use the PostgreSQL @c gate_type enumeration. It is built from
7 * the persistent mmap representation (via @c createGenericCircuit() /
8 * @c getGenericCircuit()) and then evaluated over an arbitrary semiring
9 * using the @c evaluate() template method.
10 *
11 * Beyond the gate/wire data inherited from @c Circuit<gate_type>,
12 * @c GenericCircuit tracks:
13 * - Per-gate integer annotation pairs (@c info1, @c info2) used by
14 * aggregation and semimodule gates.
15 * - Per-gate variable-length string extras (e.g. label strings for
16 * @c gate_value gates).
17 * - A probability vector for probabilistic evaluation.
18 * - The set of input gate IDs (for semiring evaluation traversal).
19 *
20 * The circuit is Boost-serialisable, which is used when sending it as
21 * a blob to an external knowledge-compiler process.
22 */
23#ifndef GENERIC_CIRCUIT_H
24#define GENERIC_CIRCUIT_H
25
26#include <map>
27#include <type_traits>
28
29#include <boost/archive/binary_oarchive.hpp>
30#include <boost/serialization/unordered_map.hpp>
31#include <boost/serialization/map.hpp>
32#include <boost/serialization/set.hpp>
33#include <boost/serialization/vector.hpp>
34
35#include "Circuit.h"
36#include "semiring/Semiring.h"
37
38extern "C" {
39#include "provsql_utils.h"
40}
41
42/**
43 * @brief In-memory provenance circuit with semiring-generic evaluation.
44 *
45 * Gate types are the PostgreSQL @c gate_type values. The circuit is
46 * constructed from the persistent mmap store and then evaluated in-memory.
47 */
48class GenericCircuit : public Circuit<gate_type>
49{
50private:
51std::map<gate_t, std::pair<unsigned,unsigned> > infos; ///< Per-gate (info1, info2) annotations
52std::map<gate_t, std::string> extra; ///< Per-gate string extras
53std::set<gate_t> inputs; ///< Set of input (leaf) gate IDs
54std::vector<double> prob; ///< Per-gate probability values
55std::set<gate_t> boolean_assumed_gates; ///< Side-band Boolean-assumption marker set by @c foldBooleanIdentities ; an evaluator visiting a gate in this set refuses to proceed under a semiring that does not admit a homomorphism from Boolean functions. In-memory only ; never persisted to mmap. Distinct from the @c gate_assumed_boolean enum (used by the safe-query rewriter to encode the same restriction at the persistent layer).
56
57public:
58/**
59 * @brief Return a placeholder debug string (not intended for display).
60 * @param g Gate identifier (unused).
61 * @return Fixed placeholder string @c "<GenericCircuit>".
62 */
63virtual std::string toString(gate_t g) const override {
64 return "<GenericCircuit>";
65}
66
67/**
68 * @brief Set the integer annotation pair for gate @p g.
69 * @param g Gate identifier.
70 * @param info1 First annotation integer.
71 * @param info2 Second annotation integer.
72 */
73void setInfos(gate_t g, unsigned info1, unsigned info2)
74{
75 infos[g]=std::make_pair(info1, info2);
76}
77
78/**
79 * @brief Return the integer annotation pair for gate @p g.
80 * @param g Gate identifier.
81 * @return @c {info1, info2}, or @c {-1,-1} if not set.
82 */
83std::pair<unsigned,unsigned> getInfos(gate_t g) const
84{
85 auto it = infos.find(g);
86 if(it==infos.end())
87 return std::make_pair(-1, -1);
88 return it->second;
89}
90
91/**
92 * @brief Attach a string extra to gate @p g.
93 * @param g Gate identifier.
94 * @param ex String to store.
95 */
96void setExtra(gate_t g, const std::string &ex)
97{
98 extra[g]=ex;
99}
100
101/**
102 * @brief Return the string extra for gate @p g.
103 * @param g Gate identifier.
104 * @return The stored string, or empty if not set.
105 */
106std::string getExtra(gate_t g) const
107{
108 auto it = extra.find(g);
109 if(it==extra.end())
110 return "";
111 else
112 return it->second;
113}
114
115/** @copydoc Circuit::addGate() */
116gate_t addGate() override;
117/** @copydoc Circuit::setGate(gateType) */
118gate_t setGate(gate_type type) override;
119/** @copydoc Circuit::setGate(const uuid&, gateType) */
120gate_t setGate(const uuid &u, gate_type type) override;
121
122/**
123 * @brief Return the set of input (leaf) gates.
124 * @return Const reference to the set of input gate identifiers.
125 */
126const std::set<gate_t> &getInputs() const {
127 return inputs;
128}
129
130/**
131 * @brief Set the probability for gate @p g.
132 * @param g Gate identifier.
133 * @param p Probability in [0, 1].
134 */
135void setProb(gate_t g, double p) {
136 prob[static_cast<std::underlying_type<gate_t>::type>(g)]=p;
137}
138
139/**
140 * @brief Return the probability for gate @p g.
141 * @param g Gate identifier.
142 * @return The stored probability.
143 */
144double getProb(gate_t g) const {
145 return prob[static_cast<std::underlying_type<gate_t>::type>(g)];
146}
147
148/**
149 * @brief Replace a @c gate_cmp by a constant Boolean leaf
150 * (@c gate_one for @p p == 1, @c gate_zero for @p p == 0)
151 * or by a Bernoulli @c gate_input for any other @p p.
152 *
153 * Used by peephole pruning passes when a comparator's probability is
154 * provably 0, 1, or a closed-form value. Distinguishing the
155 * 0 / 1 case from the fractional case matters because non-probabilistic
156 * semirings (e.g. @c sr_formula, @c sr_counting) have well-defined
157 * @c zero() / @c one() values but no notion of "Bernoulli with
158 * probability @c p" &ndash; an unknown @c gate_input would default
159 * to @c semiring.one() in every semiring (per
160 * @c GenericCircuit::evaluate), which is wrong for an
161 * always-false comparator. Using @c gate_zero / @c gate_one
162 * directly is universally correct: every semiring knows its
163 * identities.
164 *
165 * Fractional probabilities are still encoded as @c gate_input + a
166 * probability so probability evaluators (MC, independent, treedec,
167 * d-DNNF, d4) can consume them, but only those evaluators handle
168 * non-trivial probabilities meaningfully. Such resolutions should
169 * therefore be confined to passes invoked from a probability
170 * context (not the universal @c getGenericCircuit-time pass).
171 *
172 * Operates on the in-memory circuit only; the persistent mmap store
173 * is never mutated. Children that become orphaned are not reaped
174 * here.
175 */
176void resolveCmpToBernoulli(gate_t g, double p) {
177 if (p == 0.0) {
179 } else if (p == 1.0) {
181 } else {
183 setProb(g, p);
184 inputs.insert(g);
185 }
186 getWires(g).clear();
187 infos.erase(g);
188 extra.erase(g);
189}
190
191/**
192 * @brief Replace an arbitrary gate (typically @c gate_times) by
193 * @c gate_zero.
194 *
195 * Used by RangeCheck's joint-conjunction pass when an AND of cmps
196 * over a shared RV constrains its support to an empty interval:
197 * since @c gate_zero is the multiplicative absorber in every
198 * semiring, replacing a @c gate_times with it is universally sound,
199 * and orphans the conjuncts (their effects are now unreachable
200 * from the root, regardless of what each individual cmp would
201 * resolve to).
202 *
203 * The wires, infos and extra fields are cleared so the gate is a
204 * proper leaf. Operates on the in-memory circuit only.
205 */
208 getWires(g).clear();
209 infos.erase(g);
210 extra.erase(g);
211}
212
213/**
214 * @brief Rewrite an arbitrary gate as a @c gate_value carrying the
215 * textual extra @p s.
216 *
217 * Used by the @c HybridEvaluator simplifier when a @c gate_arith
218 * subtree constant-folds to a scalar. Same wire/info/extra clearing
219 * as @c resolveCmpToBernoulli &ndash; the old children become
220 * orphans relative to @p g. @p s is interpreted by the consumer
221 * via @c parseDoubleStrict (or analogous routines), so it must be
222 * a canonical textual representation that round-trips through
223 * @c std::stod. Operates on the in-memory circuit only.
224 */
225void resolveToValue(gate_t g, const std::string &s) {
227 getWires(g).clear();
228 infos.erase(g);
229 extra[g] = s;
230}
231
232/**
233 * @brief Rewrite an arbitrary gate as a @c gate_rv carrying the
234 * distribution-spec extra @p s.
235 *
236 * Used by the @c HybridEvaluator simplifier when a linear
237 * combination of independent normals (or i.i.d. exponentials with
238 * the same rate) collapses to a single closed-form distribution.
239 * @p s must be a textual encoding parseable by
240 * @c parse_distribution_spec. Same wire/info clearing as
241 * @c resolveCmpToBernoulli. Operates on the in-memory circuit only.
242 */
243void resolveToRv(gate_t g, const std::string &s) {
245 getWires(g).clear();
246 infos.erase(g);
247 extra[g] = s;
248}
249
250/**
251 * @brief Drop semiring identity wires and collapse single-wire
252 * @c gate_times / @c gate_plus to their lone non-identity
253 * child; collapse a @c gate_times containing a @c gate_zero
254 * wire to that absorber.
255 *
256 * Universal rewrite: the multiplicative identity (@c gate_one), the
257 * additive identity (@c gate_zero), and the multiplicative absorber
258 * (@c gate_zero) hold across every provsql semiring, so a single
259 * pass after @c RangeCheck is sound for every downstream consumer
260 * (probability_evaluate, to_provxml, view_circuit, Studio's
261 * simplified subgraph). Does NOT apply the additive absorber
262 * rewrite (@c plus-with-one): @c gate_one only absorbs in
263 * idempotent semirings (Boolean, MinMax), so applying it
264 * unconditionally would silently change the semantics for
265 * @c Counting / @c Formula / etc.
266 *
267 * Operates on the in-memory circuit only; the persistent mmap store
268 * is never touched. Gated alongside @c RangeCheck by
269 * @c provsql.simplify_on_load.
270 */
272
273/**
274 * @brief Apply Boolean-only simplification rules to @c gate_plus and
275 * @c gate_times. Each rule fires by mutating the gate's
276 * wires in place AND adding the gate to
277 * @c boolean_assumed_gates so semiring evaluators that do
278 * not admit a homomorphism from Boolean functions refuse to
279 * proceed.
280 *
281 * Rules :
282 * - @b Idempotence : @c gate_plus(a, a, b) → @c gate_plus(a, b),
283 * @c gate_times(a, a, b) → @c gate_times(a, b). Child dedup by
284 * gate id ; preserves first-occurrence order.
285 * - @b Plus-with-one @b absorber :
286 * @c gate_plus(..., @c gate_one, ...) → @c gate_one (rewires to
287 * an empty plus then collapses to @c gate_one).
288 *
289 * Operates on the in-memory @c GenericCircuit only ; the persistent
290 * mmap store is never mutated, and the gate's UUID-to-@c gate_t
291 * mapping survives so callers indexing by the original UUID still
292 * find it. Re-runs @c foldSemiringIdentities at the end to collapse
293 * single-wire @c gate_plus / @c gate_times residues the dedup may
294 * have left behind.
295 */
297
298/**
299 * @brief Mark gate @p g as Boolean-assumed (in-memory side band).
300 * Visited by every @c evaluate<S> traversal : if @p g is in
301 * the set, the visit checks @c S::compatibleWithBooleanRewrite
302 * and throws a @c CircuitException otherwise.
303 */
305
306/** @brief Report whether @p g carries the Boolean-assumption flag. */
308 return boolean_assumed_gates.count(g) > 0;
309}
310
311/**
312 * @brief Replace the wires of @p g with @p w.
313 *
314 * Used by the @c HybridEvaluator simplifier's identity-element drop
315 * to remove constant-zero wires from a @c PLUS gate (or constant-one
316 * wires from a @c TIMES gate) without changing the gate's type.
317 * Dropped children become orphans relative to @p g.
318 */
319void setWires(gate_t g, std::vector<gate_t> w) {
320 getWires(g) = std::move(w);
321}
322
323/**
324 * @brief Rewrite an arbitrary gate as a @c gate_plus over @p w.
325 *
326 * Used by the @c HybridEvaluator multi-cmp island decomposer when
327 * a comparator from a shared-island group is rewritten as the OR
328 * of the joint-table @c gate_mulinput leaves where the comparator's
329 * bit is set. Clears infos and extra and installs the new wires.
330 */
331void resolveToPlus(gate_t g, std::vector<gate_t> w) {
333 getWires(g) = std::move(w);
334 infos.erase(g);
335 extra.erase(g);
336}
337
338/**
339 * @brief Allocate a fresh @c gate_input gate carrying probability
340 * @p p, with a unique synthetic UUID so subsequent
341 * @c BooleanCircuit conversion does not collide multiple
342 * no-UUID inputs onto the same gate.
343 *
344 * The synthetic UUID is derived from the freshly-assigned gate id;
345 * it is not a real v4 UUID (does not match the @c xxxxxxxx-...
346 * format) and exists only for in-memory uniqueness during the
347 * probability_evaluate pipeline. The gate is added to @c inputs
348 * so the conversion's first loop maps it into @c BooleanCircuit's
349 * @c gc_to_bc.
350 *
351 * @param p Probability for the new input.
352 * @return The id of the new gate.
353 */
355 gate_t id = addGate();
357 setProb(id, p);
358 std::string u = "dec-in-" + std::to_string(static_cast<size_t>(id));
359 uuid2id[u] = id;
360 id2uuid[id] = u;
361 inputs.insert(id);
362 return id;
363}
364
365/**
366 * @brief Allocate a fresh @c gate_mulinput gate with key @p key,
367 * probability @p p, and value index @p value_index.
368 *
369 * Used by the joint-table decomposer to materialise one Bernoulli
370 * outcome of a 2^k-way categorical distribution over a shared
371 * continuous island. All mulinputs in one joint table share the
372 * same @p key (the block anchor returned by @c addAnonymousInputGate);
373 * @p value_index is stored in @c info1 so
374 * @c BooleanCircuit::independentEvaluation can group / dedup
375 * MULIN references at OR sites. A unique synthetic UUID is
376 * minted for the same reason as @c addAnonymousInputGate.
377 */
379 unsigned value_index) {
380 gate_t id = addGate();
382 setProb(id, p);
383 setInfos(id, value_index, 0);
384 getWires(id).push_back(key);
385 std::string u = "dec-mul-" + std::to_string(static_cast<size_t>(id));
386 uuid2id[u] = id;
387 id2uuid[id] = u;
388 return id;
389}
390
391/**
392 * @brief Allocate a fresh @c gate_arith gate with operator tag @p op
393 * and the given @p wires.
394 *
395 * Used by the @c HybridEvaluator simplifier's mixture-lift rule when
396 * pushing a @c PLUS / @c TIMES inside a mixture's two scalar branches:
397 * each branch needs a fresh @c gate_arith child carrying the lifted
398 * operation, and those children must round-trip through downstream
399 * @c id2uuid / @c uuid2id lookups (Studio's simplified subgraph,
400 * @c to_provxml). A unique synthetic UUID is minted for the same
401 * reason as @c addAnonymousInputGate.
402 */
404 std::vector<gate_t> wires_) {
405 gate_t id = addGate();
407 setInfos(id, static_cast<int>(op), 0);
408 getWires(id) = std::move(wires_);
409 std::string u = "dec-arith-" + std::to_string(static_cast<size_t>(id));
410 uuid2id[u] = id;
411 id2uuid[id] = u;
412 return id;
413}
414
415/**
416 * @brief Allocate a fresh @c gate_value gate carrying the textual
417 * scalar @p text.
418 *
419 * Used by the @c HybridEvaluator simplifier's PLUS coefficient
420 * aggregation rule: when same-RV terms in a @c PLUS gate are merged
421 * into <tt>arith(TIMES, value:a_total, Z)</tt> per RV, each
422 * coefficient @c a_total needs a fresh @c gate_value to feed the
423 * synthetic @c TIMES. @p text must be a canonical text form that
424 * round-trips through @c parseDoubleStrict (the simplifier already
425 * formats with precision 17). A unique synthetic UUID is minted for
426 * the same reason as @c addAnonymousInputGate.
427 */
428gate_t addAnonymousValueGate(const std::string &text) {
429 gate_t id = addGate();
431 setExtra(id, text);
432 std::string u = "dec-value-" + std::to_string(static_cast<size_t>(id));
433 uuid2id[u] = id;
434 id2uuid[id] = u;
435 return id;
436}
437
438/**
439 * @brief Rewrite @p g in place as a @c gate_mixture over the wires
440 * @c [p_token, x_token, y_token].
441 *
442 * Used by the @c HybridEvaluator simplifier's mixture-lift rule when
443 * a @c gate_arith containing a single @c gate_mixture child is pushed
444 * inside the mixture's branches: the outer arith gate is rewritten in
445 * place as the lifted mixture, preserving its UUID and the
446 * non-mixture-aware code paths that already hold references to it.
447 * The @p p_token is reused verbatim so Bernoulli identity is
448 * preserved across the rewrite; the @p x_token and @p y_token are
449 * the freshly-minted arith children built via
450 * @c addAnonymousArithGate.
451 */
453 gate_t x_token, gate_t y_token) {
455 std::vector<gate_t> w;
456 w.reserve(3);
457 w.push_back(p_token);
458 w.push_back(x_token);
459 w.push_back(y_token);
460 getWires(g) = std::move(w);
461 infos.erase(g);
462 extra.erase(g);
463}
464
465/**
466 * @brief Allocate a fresh @c gate_mulinput labelled with a numeric
467 * outcome value carried in @c extra.
468 *
469 * Variant of @c addAnonymousMulinputGate used by the categorical
470 * mixture lowering: the mulinput's @c info1 still holds the ordinal
471 * @p value_index for @c independentEvaluation's dedup, and the
472 * outcome's numeric label is stored in @c extra so the evaluator-side
473 * categorical-mixture handlers can read it as a @c float8.
474 */
476 unsigned value_index,
477 const std::string &value_text) {
478 gate_t id = addAnonymousMulinputGate(key, p, value_index);
479 setExtra(id, value_text);
480 return id;
481}
482
483/**
484 * @brief Rewrite @p g in place as a categorical-form @c gate_mixture
485 * over @p wires (@c [key, mul_1, ..., mul_n]).
486 *
487 * Used by the explicit @c provsql.categorical constructor (built at
488 * SQL-call time, not by the simplifier): the @c gate_mixture type is
489 * reused with @c N > 3 wires, where @c wires[0] is a fresh
490 * @c gate_input "key" anchor (its own probability is irrelevant: the
491 * categorical mass is on the mulinputs) and @c wires[1..n] are
492 * @c gate_mulinput leaves sharing that key. Every @c gate_mixture
493 * handler downstream branches on <tt>wires.size() == 3</tt> for the
494 * classic <tt>[p_token, x_token, y_token]</tt> shape vs the
495 * categorical shape; the latter is what unlocks closed-form CDF /
496 * cmp evaluation via @c AnalyticEvaluator.
497 */
498void resolveToCategoricalMixture(gate_t g, std::vector<gate_t> wires_) {
500 getWires(g) = std::move(wires_);
501 infos.erase(g);
502 extra.erase(g);
503}
504
505/**
506 * @brief Test whether @p g is a categorical-form @c gate_mixture
507 * (the explicit @c provsql.categorical output).
508 *
509 * Returns true iff @p g is a @c gate_mixture whose wires are
510 * @c [key, mul_1, ..., mul_n] with @p n &ge; 1: @c wires[0] a
511 * @c gate_input key anchor, and every subsequent wire a
512 * @c gate_mulinput. The classic mixture shape
513 * @c [p_token, x_token, y_token] returns false (one or both of
514 * @c wires[1..2] are not @c gate_mulinput).
515 */
517{
518 if (getGateType(g) != gate_mixture) return false;
519 const auto &w = getWires(g);
520 if (w.size() < 2) return false;
521 if (getGateType(w[0]) != gate_input) return false;
522 for (std::size_t i = 1; i < w.size(); ++i) {
523 if (getGateType(w[i]) != gate_mulinput) return false;
524 }
525 return true;
526}
527
528/**
529 * @brief Boost serialisation support.
530 * @param ar Boost archive (input or output).
531 * @param version Archive version (unused).
532 */
533template<class Archive>
534void serialize (Archive & ar, const unsigned int version)
535{
536 ar & uuid2id;
537 ar & id2uuid;
538 ar & gates;
539 ar & wires;
540 ar & infos;
541 ar & extra;
542 ar & inputs;
543 ar & prob;
544}
545
548
549/**
550 * @brief Evaluate the sub-circuit rooted at gate @p g over semiring @p semiring.
551 *
552 * Performs a post-order traversal from @p g, mapping each input gate to
553 * its semiring value via @p provenance_mapping, and combining the results
554 * using the semiring operations.
555 *
556 * @tparam S A concrete @c semiring::Semiring subclass.
557 * @param g Root gate of the sub-circuit to evaluate.
558 * @param provenance_mapping Map from input gate IDs to semiring values.
559 * @param semiring Semiring instance providing @c zero(), @c one(),
560 * @c plus(), @c times(), etc.
561 * @return The semiring value of the circuit at gate @p g.
562 */
563template<typename S, std::enable_if_t<std::is_base_of_v<semiring::Semiring<typename S::value_type>, S>, int> = 0>
564typename S::value_type evaluate(gate_t g, std::unordered_map<gate_t, typename S::value_type> &provenance_mapping, S semiring) const;
565};
566
567#endif /* GENERIC_CIRCUIT_H */
Generic directed-acyclic-graph circuit template and gate identifier.
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:49
Abstract semiring interface for provenance evaluation.
Generic template base class for provenance circuits.
Definition Circuit.h:62
std::string uuid
Definition Circuit.h:65
std::vector< gate_t > & getWires(gate_t g)
Definition Circuit.h:140
gate_type getGateType(gate_t g) const
Definition Circuit.h:130
std::unordered_map< gate_t, uuid > id2uuid
Definition Circuit.h:69
std::unordered_map< uuid, gate_t > uuid2id
Definition Circuit.h:68
void setGateType(gate_t g, gate_type t)
Definition Circuit.h:79
std::vector< gate_type > gates
Definition Circuit.h:71
std::vector< std::vector< gate_t > > wires
Definition Circuit.h:72
In-memory provenance circuit with semiring-generic evaluation.
void resolveToPlus(gate_t g, std::vector< gate_t > w)
Rewrite an arbitrary gate as a gate_plus over w.
void resolveToCategoricalMixture(gate_t g, std::vector< gate_t > wires_)
Rewrite g in place as a categorical-form gate_mixture over wires ([key, mul_1, ......
void resolveGateToZero(gate_t g)
Replace an arbitrary gate (typically gate_times) by gate_zero.
void setWires(gate_t g, std::vector< gate_t > w)
Replace the wires of g with w.
std::map< gate_t, std::pair< unsigned, unsigned > > infos
Per-gate (info1, info2) annotations.
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.
gate_t addAnonymousMulinputGateWithValue(gate_t key, double p, unsigned value_index, const std::string &value_text)
Allocate a fresh gate_mulinput labelled with a numeric outcome value carried in extra.
void resolveToRv(gate_t g, const std::string &s)
Rewrite an arbitrary gate as a gate_rv carrying the distribution-spec extra s.
void resolveToMixture(gate_t g, gate_t p_token, gate_t x_token, gate_t y_token)
Rewrite g in place as a gate_mixture over the wires [p_token, x_token, y_token].
std::map< gate_t, std::string > extra
Per-gate string extras.
gate_t addGate() override
Allocate a new gate with a default-initialised type.
std::set< gate_t > inputs
Set of input (leaf) gate IDs.
void foldSemiringIdentities()
Drop semiring identity wires and collapse single-wire gate_times / gate_plus to their lone non-identi...
gate_t addAnonymousArithGate(provsql_arith_op op, std::vector< gate_t > wires_)
Allocate a fresh gate_arith gate with operator tag op and the given wires.
gate_t addAnonymousValueGate(const std::string &text)
Allocate a fresh gate_value gate carrying the textual scalar text.
void serialize(Archive &ar, const unsigned int version)
Boost serialisation support.
friend class dDNNFTreeDecompositionBuilder
bool isCategoricalMixture(gate_t g) const
Test whether g is a categorical-form gate_mixture (the explicit provsql.categorical output).
std::vector< double > prob
Per-gate probability values.
void setInfos(gate_t g, unsigned info1, unsigned info2)
Set the integer annotation pair for gate g.
std::string getExtra(gate_t g) const
Return the string extra for gate g.
gate_t setGate(gate_type type) override
Allocate a new gate with type type and no UUID.
void markBooleanAssumed(gate_t g)
Mark gate g as Boolean-assumed (in-memory side band).
std::set< gate_t > boolean_assumed_gates
Side-band Boolean-assumption marker set by foldBooleanIdentities ; an evaluator visiting a gate in th...
double getProb(gate_t g) const
Return the probability for gate g.
void resolveCmpToBernoulli(gate_t g, double p)
Replace a gate_cmp by a constant Boolean leaf (gate_one for p == 1, gate_zero for p == 0) or by a Ber...
gate_t addAnonymousInputGate(double p)
Allocate a fresh gate_input gate carrying probability p, with a unique synthetic UUID so subsequent B...
friend class boost::serialization::access
const std::set< gate_t > & getInputs() const
Return the set of input (leaf) gates.
bool isBooleanAssumed(gate_t g) const
Report whether g carries the Boolean-assumption flag.
std::pair< unsigned, unsigned > getInfos(gate_t g) const
Return the integer annotation pair for gate g.
void setExtra(gate_t g, const std::string &ex)
Attach a string extra to gate g.
virtual std::string toString(gate_t g) const override
Return a placeholder debug string (not intended for display).
gate_t addAnonymousMulinputGate(gate_t key, double p, unsigned value_index)
Allocate a fresh gate_mulinput gate with key key, probability p, and value index value_index.
void resolveToValue(gate_t g, const std::string &s)
Rewrite an arbitrary gate as a gate_value carrying the textual extra s.
void foldBooleanIdentities()
Apply Boolean-only simplification rules to gate_plus and gate_times.
void setProb(gate_t g, double p)
Set the probability for gate g.
Core types, constants, and utilities shared across ProvSQL.
provsql_arith_op
Arithmetic operator tags used by gate_arith.
@ gate_rv
Continuous random-variable leaf (extra encodes distribution).
@ gate_mixture
Probabilistic mixture: three wires [p_token (gate_input Bernoulli), x_token, y_token]; samples x when...
@ gate_arith
n-ary arithmetic gate over scalar-valued children (info1 holds operator tag)