ProvSQL C/C++ API
Adding support for provenance and uncertainty management to PostgreSQL databases
Loading...
Searching...
No Matches
CmpEvaluatorCommon.cpp
Go to the documentation of this file.
1/**
2 * @file CmpEvaluatorCommon.cpp
3 * @brief Implementation of the shared HAVING @c gate_cmp evaluator
4 * machinery. See @c CmpEvaluatorCommon.h.
5 */
7
8#include <algorithm>
9
10#include "having_semantics.hpp" // extract_constant_string, semimod_extract_string_and_K, map_cmp_op, flip_op
11extern "C" {
12#include "provsql_utils.h" // gate_type enum
13}
14
15namespace provsql {
16
18{
19 const auto &cw = gc.getWires(cmp);
20 if (cw.size() != 2) return false;
21
22 bool okop = false;
24 if (!okop) return false;
25
26 /* Identify the gate_agg side; the other is the threshold constant.
27 * The reversed order (const compared to agg) calls for op flipping. */
28 gate_t agg_side, const_side;
29 if (gc.getGateType(cw[0]) == gate_agg) {
30 agg_side = cw[0]; const_side = cw[1];
31 } else if (gc.getGateType(cw[1]) == gate_agg) {
32 agg_side = cw[1]; const_side = cw[0];
34 } else {
35 return false;
36 }
37
38 /* The comparison domain is the aggregate result type (info2 of the
39 * gate_agg). The closed-form evaluators handle the ordered numeric
40 * domains (int / numeric / float) by scaling every value and the
41 * threshold to a common integer grid from their decimal text -- so a
42 * numeric(p,d) or finite-decimal float column is exact and fractional
43 * thresholds work. Text aggregates, exponential / non-decimal values,
44 * and grids too wide for a @c long are declined here and left to the
45 * enumeration path. */
46 const unsigned aggtype =
47 gc.getInfos(agg_side).second & PROVSQL_AGG_TYPE_MASK; // strip scalar flag
48 if (provsql_having_detail::aggtype_is_text(aggtype)) return false;
49
50 std::string c_str;
51 if (!provsql_having_detail::extract_constant_string(gc, const_side, c_str))
52 return false;
53 long c_mant = 0; int c_scale = 0;
54 if (!provsql_having_detail::parse_decimal_scaled(c_str, c_mant, c_scale))
55 return false;
56
57 const auto &agg_children = gc.getWires(agg_side);
58 if (agg_children.empty()) return false;
59
60 std::vector<gate_t> semimods, ks;
61 std::vector<long> m_mant;
62 std::vector<int> m_scale;
63 semimods.reserve(agg_children.size());
64 ks.reserve(agg_children.size());
65 m_mant.reserve(agg_children.size());
66 m_scale.reserve(agg_children.size());
67
68 for (gate_t ch : agg_children) {
69 if (gc.getGateType(ch) != gate_semimod) return false;
70 std::string m_str;
71 gate_t k_gate{};
73 return false;
74 long mm = 0; int sc = 0;
76 return false;
77 semimods.push_back(ch);
78 ks.push_back(k_gate);
79 m_mant.push_back(mm);
80 m_scale.push_back(sc);
81 }
82
83 /* Effective aggregate kind. COUNT(*) reaches the circuit as SUM of
84 * unit-weighted semimods (detected on the unscaled mantissas); mirror
85 * pw_from_cmp_gate's remap so callers see COUNT in that case. */
86 AggregationOperator agg_kind =
87 getAggregationOperator(gc.getInfos(agg_side).first);
88 if (agg_kind == AggregationOperator::SUM) {
89 bool all_one = true;
90 for (std::size_t i = 0; i < m_mant.size(); ++i)
91 if (!(m_mant[i] == 1 && m_scale[i] == 0)) { all_one = false; break; }
92 if (all_one) agg_kind = AggregationOperator::COUNT;
93 }
94
95 /* Rescale every value and the threshold to a common integer grid. */
96 int target = c_scale;
97 for (int s : m_scale) target = std::max(target, s);
98 long C = 0;
99 if (!provsql_having_detail::rescale_to(c_mant, c_scale, target, C)) return false;
100 std::vector<long> ms(m_mant.size());
101 for (std::size_t i = 0; i < m_mant.size(); ++i)
102 if (!provsql_having_detail::rescale_to(m_mant[i], m_scale[i], target, ms[i]))
103 return false;
104
105 out.agg = agg_side;
106 out.semimods = std::move(semimods);
107 out.ks = std::move(ks);
108 out.ms = std::move(ms);
109 out.agg_kind = agg_kind;
110 out.op = op;
111 out.C = C;
112 return true;
113}
114
115std::vector<unsigned> computeRefCounts(const GenericCircuit &gc)
116{
117 const auto nb = gc.getNbGates();
118 std::vector<unsigned> ref(nb, 0);
119 for (std::size_t i = 0; i < nb; ++i) {
120 auto g = static_cast<gate_t>(i);
121 for (gate_t w : gc.getWires(g)) {
122 const auto idx = static_cast<std::size_t>(w);
123 if (idx < ref.size()) ++ref[idx];
124 }
125 }
126 return ref;
127}
128
130 const std::vector<unsigned> &ref, bool &ok)
131{
132 switch (gc.getGateType(g)) {
133 case gate_one: return 1.0;
134 case gate_zero: return 0.0;
135 case gate_input:
136 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
137 return gc.getProb(g);
138 case gate_times: {
139 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
140 double pr = 1.0;
141 for (gate_t c : gc.getWires(g)) {
142 pr *= contributorProb(gc, c, ref, ok);
143 if (!ok) return 0.0;
144 }
145 return pr;
146 }
147 case gate_plus: {
148 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
149 double q = 1.0;
150 for (gate_t c : gc.getWires(g)) {
151 q *= (1.0 - contributorProb(gc, c, ref, ok));
152 if (!ok) return 0.0;
153 }
154 return 1.0 - q;
155 }
156 case gate_monus: {
157 /* a (-) b = a AND NOT b ; with disjoint private leaves a and b are
158 * independent, so Pr = Pr(a) * (1 - Pr(b)). Children are
159 * [minuend, subtrahend] (see GenericCircuit evaluate<S>). */
160 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
161 const auto &w = gc.getWires(g);
162 if (w.size() != 2) { ok = false; return 0.0; }
163 double pa = contributorProb(gc, w[0], ref, ok);
164 if (!ok) return 0.0;
165 double pb = contributorProb(gc, w[1], ref, ok);
166 if (!ok) return 0.0;
167 return pa * (1.0 - pb);
168 }
169 default:
170 ok = false;
171 return 0.0;
172 }
173}
174
175} // namespace provsql
AggregationOperator getAggregationOperator(Oid oid)
Map a PostgreSQL aggregate function OID to an AggregationOperator.
AggregationOperator
SQL aggregation functions tracked by ProvSQL.
Definition Aggregation.h:51
@ COUNT
COUNT(*) or COUNT(expr) → integer.
Definition Aggregation.h:52
@ SUM
SUM → integer or float.
Definition Aggregation.h:53
ComparisonOperator
SQL comparison operators used in gate_cmp circuit gates.
Definition Aggregation.h:39
gate_t
Strongly-typed gate identifier.
Definition Circuit.h:49
Shared machinery for the closed-form HAVING gate_cmp probability evaluators (Poisson-binomial COUNT,...
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
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.
double getProb(gate_t g) const
Return the probability for gate g.
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 rescale_to(long mantissa, int scale, int target_scale, long &out)
bool aggtype_is_text(unsigned oid)
ComparisonOperator flip_op(ComparisonOperator op)
bool parse_decimal_scaled(const std::string &s, long &mantissa, int &scale)
ComparisonOperator map_cmp_op(GenericCircuit &c, gate_t cmp_gate, bool &ok)
bool semimod_extract_string_and_K(GenericCircuit &c, gate_t semimod_gate, std::string &m_out, gate_t &k_gate_out)
bool extract_constant_string(GenericCircuit &c, gate_t x, std::string &C_out)
std::vector< unsigned > computeRefCounts(const GenericCircuit &gc)
Reference count of every gate as a wire-target across the whole circuit.
bool matchAggCmp(GenericCircuit &gc, gate_t cmp, AggCmpMatch &out)
Try to match cmp against gate_cmp(gate_agg(α, semimod_i(K_i, m_i)*), gate_value(C)).
double contributorProb(const GenericCircuit &gc, gate_t g, const std::vector< unsigned > &ref, bool &ok)
Read-once marginal probability of a count/aggregate contributor (the K side of a semimod).
Core types, constants, and utilities shared across ProvSQL.
#define PROVSQL_AGG_TYPE_MASK
Result of matching a gate_cmp against the canonical HAVING aggregate-comparison shape.
gate_t agg
the gate_agg operand of the cmp
long C
the constant threshold, on the same integer grid as ms
std::vector< gate_t > ks
the K side of each semimod (contributor root)
std::vector< gate_t > semimods
the per-child gate_semimod parents
std::vector< long > ms
the M side of each semimod (per-row value), scaled to a common integer grid (numeric / decimal-float ...
AggregationOperator agg_kind
effective aggregate (SUM-of-1s remapped to COUNT)
ComparisonOperator op
comparator, flipped if the agg sits on the right