ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
AggMarginalEvaluator.h
Go to the documentation of this file.
1/**
2 * @file AggMarginalEvaluator.h
3 * @brief Exact closed-form HAVING @c COUNT(*) @c op @c C probability over
4 * *safe-join* lineage -- the recursive marginal-vector engine of the
5 * Ré-Suciu HAVING trichotomy (see
6 * @c doc/source/dev/probability-evaluation.rst).
7 *
8 * @c CountCmpEvaluator (the flat Poisson-binomial pre-pass) is exact only
9 * when the @c gate_agg children are pairwise leaf-disjoint, i.e. flat
10 * single-table COUNT. A join makes two aggregate-input rows share a base
11 * tuple (fan-out, e.g. @c R(k,a),S(a,b) with several @c b per @c a), so the
12 * contributors stop being independent Bernoulli trials and
13 * @c CountCmpEvaluator bails to @c provsql_having's exponential enumeration.
14 *
15 * This pass generalises the flat case to any *hierarchical* (laminar) join:
16 * each contributor is a product (conjunction) of @c gate_input leaves
17 * (nested @c gate_times from SPJ subqueries / views is flattened, since
18 * @c times is AND on the probability path, so detection is invariant to
19 * join order and subquery nesting), and the count distribution is computed
20 * **recursively** down the hierarchy. At
21 * each level the contributors partition into independent **blocks** (by shared
22 * leaf); a block factors out the leaves common to *every* member (this level's
23 * shared "root" event) and the block count is the disjoint mixture
24 * @f$(1-p_{\text{root}})\,\delta_0 + p_{\text{root}}\,m_{\text{inner}}@f$ (the
25 * @c ⊥ combinator), where @f$m_{\text{inner}}@f$ is the same construction
26 * applied to the per-member residual leaf sets one level deeper; independent
27 * blocks combine by **convolution** (the @c ⊛^+ combinator). Single-level
28 * fan-out (@c R(k,a),S(a,b)) is the case where every residual is one leaf and
29 * @f$m_{\text{inner}}@f$ is a Poisson-binomial; deeper nesting (orders→items
30 * under a user) recurses further. The answer is
31 * @f$\sum_{c\ge 1,\;c\,\theta\,C} m[c]@f$ over the resulting count PMF @c m,
32 * with the empty group (@c c = 0) excluded exactly as in
33 * @c CountCmpEvaluator / SQL @c HAVING semantics.
34 *
35 * A multi-member block with *no* common leaf is the **join (Cartesian
36 * product)** node @c R(a),S(a,b),T(a,c): the contributors are the complete
37 * product of per-factor parts, so @c count is the product of the per-factor
38 * counts. A @c SUM whose value lives on one factor is @f$S_f\cdot M@f$ (that
39 * factor's weighted sum times the others' count product); a *branch-spanning*
40 * value that is **additively separable** across factors (e.g. @c sum(b+c)) is
41 * @f$\sum_f S_f\cdot\prod_{g\ne f} N_g@f$, folded exactly from the per-factor
42 * *joint* @c (sum,count) distributions (@c sumCountPMF); a
43 * **multiplicatively separable** value (e.g. @c sum(b*c)) is
44 * @f$\prod_f S_f@f$, the product of the per-factor weighted sums
45 * (@c mulSeparableSumPMF). A value that is neither (e.g. @c sum(b*c+b+c))
46 * couples the factors and self-gates back to enumeration.
47 *
48 * **Soundness is circuit-only and self-gating.** No planner-time skeleton
49 * certificate is consulted: the recursion is exact iff at every level each
50 * multi-member block has a leaf common to *all* its members (and every
51 * involved leaf is private to the cmp subtree). A non-laminar shape -- e.g.
52 * the triangle @c R(x,y),S(y,z),T(z,x) -- produces a multi-member block with
53 * no common leaf at some level, which clears the soundness flag and falls the
54 * cmp through to exact enumeration. This circuit-only recursion covers the
55 * tuple-independent hierarchical class at any depth.
56 *
57 * **BID blocks (@c COUNT / @c SUM / @c AVG / @c MIN / @c MAX).** A
58 * @c repair_key block surfaces in the circuit as a set of @c gate_mulinput
59 * contributors sharing a block-key child, mutually exclusive with
60 * per-alternative probabilities. Such a contributor is recognised and the
61 * block handled as a *categorical* (at most one alternative present, the null
62 * arm Σp_i<1 contributing 0), independent of the TID part and of other blocks:
63 * @c COUNT / @c SUM / @c AVG convolve the block's count / weighted-sum
64 * distribution, and @c MIN / @c MAX fold a per-block factor
65 * (1-Σ_{pred} p_alt) into each @c pAllAbsent over a value-thresholded subset.
66 * No planner certificate is needed, since the block *is* visible in the
67 * circuit. The residual genuinely certificate-only case is a declared key on a
68 * plain TID table (mutual exclusion in @c block_key metadata only, no
69 * @c mulinput): that would need a planner @c CERT_SAFE_AGG_PLAN.
70 *
71 * **Non-read-once UNION / EXCEPT contributors.** A @c UNION / @c EXCEPT over a
72 * join that re-uses a base tuple gives a contributor that is a @c gate_plus /
73 * @c gate_monus repeating the shared leaf -- @c (r∧s)∨(r∧t) or @c (r∧s)∖(r∧t)
74 * -- which @c contributorProb (read-once only) rejects. When the contributor's
75 * footprint is *private* (so it is independent of every other contributor),
76 * @c contributorExactMarginal computes its exact marginal by brute force over
77 * its private leaves (the internal sharing resolved exactly) and the
78 * contributor is modelled as a one-alternative BID block -- an independent
79 * event -- reusing the categorical machinery above. A base tuple shared
80 * *across* contributors of the same group is genuinely @f$\#P@f$-hard and bails.
81 *
82 * Runs as a probability-side pre-pass in @c probability_evaluate.cpp, *after*
83 * @c runCountCmpEvaluator (so the cheap flat path still wins where it
84 * applies; this pass only ever sees the join-shaped cmps the flat pass left
85 * behind), gated by the same @c provsql.cmp_probability_evaluation GUC and
86 * sharing its sound-only contract (replace the @c gate_cmp by a Bernoulli
87 * @c gate_input, meaningless to symbolic semirings).
88 */
89#ifndef PROVSQL_AGG_MARGINAL_EVALUATOR_H
90#define PROVSQL_AGG_MARGINAL_EVALUATOR_H
91
92#include "GenericCircuit.h"
93
94namespace provsql {
95
96/**
97 * @brief Run the safe-join aggregate marginal-vector pre-pass over @p gc.
98 *
99 * For every @c gate_cmp matching the hierarchical-join shape (see file
100 * docstring) over @c COUNT / @c SUM / @c MIN / @c MAX, computes the
101 * comparator's exact probability through the recursive hierarchical engine
102 * and replaces the cmp by a Bernoulli @c gate_input via
103 * @c GenericCircuit::resolveCmpToBernoulli. Leaves every other cmp
104 * untouched. COUNT / SUM use the count/weighted-sum distribution
105 * (block mixture + additive convolution); MIN / MAX reduce to a handful of
106 * "all of a value-thresholded subset absent" probabilities over the same
107 * hierarchical recursion.
108 *
109 * @param gc Circuit to mutate in place.
110 * @return Number of comparators resolved by this pass.
111 */
112unsigned runAggMarginalEvaluator(GenericCircuit &gc);
113
114} // namespace provsql
115
116#endif // PROVSQL_AGG_MARGINAL_EVALUATOR_H
Semiring-agnostic in-memory provenance circuit.
unsigned runAggMarginalEvaluator(GenericCircuit &gc)
Run the safe-join aggregate marginal-vector pre-pass over gc.