23#include "utils/lsyscache.h"
28#include <unordered_map>
29#include <unordered_set>
42static int parse_int_strict(
const std::string &s,
bool &ok) {
44 if (s.empty())
return 0;
47 int v = std::stoi(s, &idx);
48 if (idx != s.size())
return 0;
61 char *opname = get_opname(infos.first);
64 std::string s(opname);
93static bool semimod_extract_M_and_K(
101 const auto &w = c.
getWires(semimod_gate);
102 if (w.size() != 2)
return false;
106 m_out = parse_int_strict(c.
getExtra(w[1]), ok);
107 if (!ok)
return false;
133 int v = parse_int_strict(c.
getExtra(w[1]), ok);
142 std::vector<gate_t> stack;
143 stack.push_back(start);
145 std::unordered_set<gate_t> seen;
147 while (!stack.empty()) {
148 gate_t cur = stack.back();
151 if (!seen.insert(cur).second)
continue;
155 if (cw.size() == 2) {
170 for (
gate_t ch : w) stack.push_back(ch);
191template <
typename SemiringT,
typename MapT>
198 std::vector<gate_t> cmp_gates;
199 collect_sp_cmp_gates(c, g, cmp_gates);
201 if (cmp_gates.empty())
204 auto pw_from_cmp_gate = [&](
gate_t cmp_gate,
typename SemiringT::value_type &pw_out) ->
bool {
205 const auto &cw = c.
getWires(cmp_gate);
206 if (cw.size() != 2)
return false;
213 if (!okop)
return false;
217 if (!extract_constant_C(c, const_side, C))
return false;
221 const auto &children = c.
getWires(agg_side);
223 std::vector<long> mvals;
224 mvals.reserve(children.size());
226 std::vector<typename SemiringT::value_type> kvals;
227 kvals.reserve(children.size());
229 for (
gate_t ch : children) {
234 if (!semimod_extract_M_and_K(c, ch, m, k_gate))
return false;
236 auto kval = c.
evaluate<SemiringT>(k_gate, mapping, S);
239 kvals.push_back(std::move(kval));
246 bool all_one_mvals =
true;
247 for (
int m : mvals) {
248 if (m != 1) { all_one_mvals =
false;
break; }
256 if (worlds.empty()) {
261 std::vector<typename SemiringT::value_type> disjuncts;
262 disjuncts.reserve(worlds.size());
264 const size_t n = kvals.size();
266 for (
auto mask : worlds) {
267 std::vector<typename SemiringT::value_type> present;
268 std::vector<typename SemiringT::value_type> missing;
272 for (
size_t i = 0; i < n; ++i) {
274 if(kvals[i]!=S.one())
275 present.push_back(kvals[i]);
285 if(kvals[i]!=S.zero())
286 missing.push_back(kvals[i]);
290 auto present_prod = S.times(present);
292 if (missing.empty()) {
293 disjuncts.push_back(std::move(present_prod));
295 auto missing_sum = S.plus(missing);
296 auto monus_factor = S.monus(S.one(), missing_sum);
297 auto term = monus_factor;
298 if(present_prod!=S.one())
299 term = S.times(std::vector<typename SemiringT::value_type>{present_prod, monus_factor});
300 disjuncts.push_back(std::move(term));
304 pw_out = S.plus(disjuncts);
309 return build_from(L, R, op);
312 return build_from(R, L, flip_op(op));
318 for (
gate_t cmp_gate : cmp_gates) {
319 typename SemiringT::value_type pw;
320 if (!pw_from_cmp_gate(cmp_gate, pw))
323 mapping[cmp_gate] = std::move(pw);
333 std::unordered_map<gate_t, std::string> &mapping)
341 std::unordered_map<gate_t, unsigned> &mapping)
349 std::unordered_map<gate_t, semiring::why_provenance_t> &mapping)
351 try_having_impl<semiring::Why>(c, g, mapping,
semiring::Why());
358 std::unordered_map<gate_t, gate_t> &mapping)
360 try_having_impl<semiring::BoolExpr>(c, g, mapping, be);
366 std::unordered_map<gate_t, bool> &mapping)
AggregationOperator getAggregationOperator(Oid oid)
Map a PostgreSQL aggregate function OID to an AggregationOperator.
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 (>=)
Boolean-expression (lineage formula) semiring.
Boolean semiring ({false, true}, ∨, ∧, false, true).
gate_t
Strongly-typed gate identifier.
Counting semiring (ℕ, +, ×, 0, 1).
Why-provenance semiring (set of witness sets).
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.
In-memory provenance circuit with semiring-generic evaluation.
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.
std::string getExtra(gate_t g) const
Return the string extra for gate g.
std::pair< unsigned, unsigned > getInfos(gate_t g) const
Return the integer annotation pair for gate g.
Provenance-as-Boolean-circuit semiring.
The Boolean semiring over bool.
The counting semiring over unsigned.
void provsql_try_having_why(GenericCircuit &c, gate_t g, std::unordered_map< gate_t, semiring::why_provenance_t > &mapping)
Evaluate the HAVING sub-circuit at g over the Why-provenance semiring.
void provsql_try_having_counting(GenericCircuit &c, gate_t g, std::unordered_map< gate_t, unsigned > &mapping)
Evaluate the HAVING sub-circuit at g over the Counting semiring.
void provsql_try_having_boolean(GenericCircuit &c, gate_t g, std::unordered_map< gate_t, bool > &mapping)
Evaluate the HAVING sub-circuit at g over the Boolean semiring.
static void try_having_impl(GenericCircuit &c, gate_t g, MapT &mapping, SemiringT S)
Rewrite HAVING comparison gates in the circuit by enumerating possible worlds.
void provsql_try_having_formula(GenericCircuit &c, gate_t g, std::unordered_map< gate_t, std::string > &mapping)
Evaluate the HAVING sub-circuit at g over the Formula semiring.
void provsql_try_having_boolexpr(GenericCircuit &c, semiring::BoolExpr &be, gate_t g, std::unordered_map< gate_t, gate_t > &mapping)
Evaluate the HAVING sub-circuit at g over the BoolExpr semiring.
Provenance evaluation helpers for HAVING-clause circuits.
@ gate_value
Scalar value (for aggregate provenance)
@ gate_agg
Aggregation operator (for aggregate provenance)
@ gate_cmp
Currently unused, meant for comparison of aggregate values.
@ gate_semimod
Semimodule scalar multiplication (for aggregate provenance)
C++ utility functions for UUID manipulation.
std::vector< mask_t > enumerate_valid_worlds(const std::vector< long > &values, int constant, ComparisonOperator op, AggregationOperator agg_kind, bool absorptive, bool &upset)
Enumerate all subsets of n tuples satisfying an aggregate predicate.
Enumerate tuple subsets satisfying an aggregate HAVING predicate.