9#include <unordered_set>
27static std::vector<double> partialPMF(
const std::vector<double> &p,
30 const std::size_t N = p.size();
31 jmax = std::min(jmax, N);
32 std::vector<double> dp(jmax + 1, 0.0);
34 for (std::size_t i = 0; i < N; ++i) {
35 const double pi = p[i];
36 const double qi = 1.0 - pi;
39 const std::size_t upper = std::min(jmax, i + 1);
40 for (std::size_t j = upper; j >= 1; --j) {
41 dp[j] = dp[j] * qi + dp[j - 1] * pi;
51static double probZero(
const std::vector<double> &p)
54 for (
double pi : p) q *= (1.0 - pi);
66static double probAtLeast(
const std::vector<double> &p,
int T)
68 const int N =
static_cast<int>(p.size());
69 if (T <= 0)
return 1.0;
70 if (T > N)
return 0.0;
73 auto dp = partialPMF(p,
static_cast<std::size_t
>(T - 1));
75 for (
int j = 0; j <= T - 1; ++j) sum += dp[j];
78 std::vector<double> q(N);
79 for (
int i = 0; i < N; ++i) q[i] = 1.0 - p[i];
80 auto dp = partialPMF(q,
static_cast<std::size_t
>(N - T));
82 for (
int j = 0; j <= N - T; ++j) sum += dp[j];
91static double probAtMost(
const std::vector<double> &p,
int T)
93 const int N =
static_cast<int>(p.size());
94 if (T < 0)
return 0.0;
95 if (T >= N)
return 1.0;
98 auto dp = partialPMF(p,
static_cast<std::size_t
>(T));
100 for (
int j = 0; j <= T; ++j) sum += dp[j];
103 std::vector<double> q(N);
104 for (
int i = 0; i < N; ++i) q[i] = 1.0 - p[i];
105 auto dp = partialPMF(q,
static_cast<std::size_t
>(N - 1 - T));
107 for (
int j = 0; j <= N - 1 - T; ++j) sum += dp[j];
116static double probEqual(
const std::vector<double> &p,
int T)
118 const int N =
static_cast<int>(p.size());
119 if (T < 0 || T > N)
return 0.0;
122 auto dp = partialPMF(p,
static_cast<std::size_t
>(T));
125 std::vector<double> q(N);
126 for (
int i = 0; i < N; ++i) q[i] = 1.0 - p[i];
127 auto dp = partialPMF(q,
static_cast<std::size_t
>(N - T));
140static double cdfForOperator(
const std::vector<double> &p,
144 const int N =
static_cast<int>(p.size());
150 return probAtLeast(p, std::max(C, 1));
153 return probAtLeast(p, std::max(C + 1, 1));
157 const int T = std::min(C, N);
158 if (T < 1)
return 0.0;
159 return probAtMost(p, T) - probZero(p);
162 const int T = std::min(C - 1, N);
163 if (T < 1)
return 0.0;
164 return probAtMost(p, T) - probZero(p);
167 if (C < 1 || C > N)
return 0.0;
168 return probEqual(p, C);
172 const double nonempty = 1.0 - probZero(p);
173 const double eq = (C >= 1 && C <= N) ? probEqual(p, C) : 0.0;
174 return nonempty - eq;
188static bool matchCountCmp(GenericCircuit &gc,
191 std::vector<gate_t> &semimods_out,
192 std::vector<gate_t> &children,
197 if (cw.size() != 2)
return false;
201 if (!okop)
return false;
207 gate_t agg_side = cw[0], const_side = cw[1];
210 agg_side = cw[1]; const_side = cw[0];
228 const auto &agg_children = gc.
getWires(agg_side);
229 if (agg_children.empty())
return false;
234 semimods_out.clear();
235 semimods_out.reserve(agg_children.size());
237 std::vector<gate_t> ks;
238 ks.reserve(agg_children.size());
240 for (
gate_t ch : agg_children) {
249 if (m != 1)
return false;
251 semimods_out.push_back(ch);
252 ks.push_back(k_gate);
256 children = std::move(ks);
263static std::vector<unsigned> computeRefCounts(
const GenericCircuit &gc)
266 std::vector<unsigned> ref(nb, 0);
267 for (std::size_t i = 0; i < nb; ++i) {
268 auto g =
static_cast<gate_t>(i);
270 const auto idx =
static_cast<std::size_t
>(w);
271 if (idx < ref.size()) ++ref[idx];
281 unsigned resolved = 0;
286 std::vector<gate_t> cmps;
287 for (std::size_t i = 0; i < nb; ++i) {
288 auto g =
static_cast<gate_t>(i);
292 if (cmps.empty())
return 0;
300 auto ref = computeRefCounts(gc);
306 std::vector<gate_t> semimods, ks;
309 if (!matchCountCmp(gc, cmp, agg, semimods, ks, op, C))
341 if (ref[
static_cast<std::size_t
>(agg)] != 1)
continue;
342 std::unordered_set<gate_t> seen;
344 for (std::size_t i = 0; i < ks.size(); ++i) {
345 if (ref[
static_cast<std::size_t
>(semimods[i])] != 1) { sound =
false;
break; }
346 if (ref[
static_cast<std::size_t
>(ks[i])] != 1) { sound =
false;
break; }
347 if (!seen.insert(ks[i]).second) { sound =
false;
break; }
349 if (!sound)
continue;
352 std::vector<double> p;
353 p.reserve(ks.size());
356 double pr = cdfForOperator(p, op, C);
359 if (pr < 0.0) pr = 0.0;
360 if (pr > 1.0) pr = 1.0;
AggregationOperator getAggregationOperator(Oid oid)
Map a PostgreSQL aggregate function OID to an AggregationOperator.
Typed aggregation value, operator, and aggregator abstractions.
AggregationOperator
SQL aggregation functions tracked by ProvSQL.
@ COUNT
COUNT(*) or COUNT(expr) → integer.
@ SUM
SUM → integer or float.
ComparisonOperator
SQL comparison operators used in gate_cmp circuit gates.
@ LE
Less than or equal (<=).
@ GE
Greater than or equal (>=).
gate_t
Strongly-typed gate identifier.
Closed-form Poisson-binomial CDF resolution for HAVING COUNT(*) op C gate_cmps.
std::vector< gate_t > & getWires(gate_t g)
Return a mutable reference to the child-wire list of gate g.
gateType getGateType(gate_t g) const
Return the type of gate g.
std::vector< gate_t >::size_type getNbGates() const
Return the total number of gates in the circuit.
In-memory provenance circuit with semiring-generic evaluation.
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...
std::pair< unsigned, unsigned > getInfos(gate_t g) const
Return the integer annotation pair for gate g.
Provenance evaluation helper for HAVING-clause circuits.
bool extract_constant_C(GenericCircuit &c, gate_t x, int &C_out)
ComparisonOperator flip_op(ComparisonOperator op)
bool semimod_extract_M_and_K(GenericCircuit &c, gate_t semimod_gate, int &m_out, gate_t &k_gate_out)
ComparisonOperator map_cmp_op(GenericCircuit &c, gate_t cmp_gate, bool &ok)
unsigned runCountCmpEvaluator(GenericCircuit &gc)
Run the Poisson-binomial pre-pass over gc.
Core types, constants, and utilities shared across ProvSQL.