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 /* The gate records the aggregate the query wrote: count(*) and count(expr)
84 * both keep COUNT even though their contributions are 1 and 0/1, so there is
85 * nothing to infer from the values here. */
86 AggregationOperator agg_kind =
87 getAggregationOperator(gc.getInfos(agg_side).first);
88
89 /* Rescale every value and the threshold to a common integer grid. */
90 int target = c_scale;
91 for (int s : m_scale) target = std::max(target, s);
92 long C = 0;
93 if (!provsql_having_detail::rescale_to(c_mant, c_scale, target, C)) return false;
94 std::vector<long> ms(m_mant.size());
95 for (std::size_t i = 0; i < m_mant.size(); ++i)
96 if (!provsql_having_detail::rescale_to(m_mant[i], m_scale[i], target, ms[i]))
97 return false;
98
99 out.agg = agg_side;
100 out.semimods = std::move(semimods);
101 out.ks = std::move(ks);
102 out.ms = std::move(ms);
103 out.agg_kind = agg_kind;
104 out.op = op;
105 out.C = C;
106 return true;
107}
108
109std::vector<unsigned> computeRefCounts(const GenericCircuit &gc)
110{
111 const auto nb = gc.getNbGates();
112 std::vector<unsigned> ref(nb, 0);
113 for (std::size_t i = 0; i < nb; ++i) {
114 auto g = static_cast<gate_t>(i);
115 for (gate_t w : gc.getWires(g)) {
116 const auto idx = static_cast<std::size_t>(w);
117 if (idx < ref.size()) ++ref[idx];
118 }
119 }
120 return ref;
121}
122
124 const std::vector<unsigned> &ref, bool &ok)
125{
126 switch (gc.getGateType(g)) {
127 case gate_one: return 1.0;
128 case gate_zero: return 0.0;
129 case gate_input:
130 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
131 return gc.getProb(g);
132 case gate_times: {
133 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
134 double pr = 1.0;
135 for (gate_t c : gc.getWires(g)) {
136 pr *= contributorProb(gc, c, ref, ok);
137 if (!ok) return 0.0;
138 }
139 return pr;
140 }
141 case gate_plus: {
142 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
143 double q = 1.0;
144 for (gate_t c : gc.getWires(g)) {
145 q *= (1.0 - contributorProb(gc, c, ref, ok));
146 if (!ok) return 0.0;
147 }
148 return 1.0 - q;
149 }
150 case gate_monus: {
151 /* a (-) b = a AND NOT b ; with disjoint private leaves a and b are
152 * independent, so Pr = Pr(a) * (1 - Pr(b)). Children are
153 * [minuend, subtrahend] (see GenericCircuit evaluate<S>). */
154 if (ref[static_cast<std::size_t>(g)] != 1) { ok = false; return 0.0; }
155 const auto &w = gc.getWires(g);
156 if (w.size() != 2) { ok = false; return 0.0; }
157 double pa = contributorProb(gc, w[0], ref, ok);
158 if (!ok) return 0.0;
159 double pb = contributorProb(gc, w[1], ref, ok);
160 if (!ok) return 0.0;
161 return pa * (1.0 - pb);
162 }
163 default:
164 ok = false;
165 return 0.0;
166 }
167}
168
169} // 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
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