59 std::vector<gate_t> stack{g};
61 while(!stack.empty()) {
62 const gate_t u = stack.back();
79 "The requested semiring does not admit a homomorphism "
80 "from Boolean functions; this gate's wires were rewritten "
81 "under a Boolean-only rule (times-idempotence or "
82 "times-absorbs-plus, applied under the 'boolean' "
83 "provenance class) and the evaluation is unsound under "
84 "this semiring. Re-run under a more general provenance "
85 "class, or pick a Boolean-compatible semiring (boolean, "
86 "boolexpr, formula, ...).");
94 && !
semiring.compatibleWithBooleanRewrite())
96 "The requested semiring is not absorptive; this gate's "
97 "wires were rewritten under an absorptive rule "
98 "(plus-idempotence, plus-with-one absorber or "
99 "plus-absorbs-times, applied under the 'absorptive' or "
100 "'boolean' provenance class) and the evaluation is "
101 "unsound under this semiring. Re-run under the "
102 "'semiring' provenance class, or pick an absorptive "
103 "semiring (probability, boolean, nonnegative "
106 if(provenance_mapping.find(u) != provenance_mapping.end()) {
117 provenance_mapping.emplace(u,
semiring.one());
129 provenance_mapping.emplace(u,
semiring.zero());
161 const std::string assumption =
getExtra(u);
162 if(assumption.empty() || assumption ==
"boolean") {
163 if(!
semiring.compatibleWithBooleanRewrite())
165 "The requested semiring does not admit a homomorphism "
166 "from Boolean functions; the wrapped sub-circuit was "
167 "computed under a Boolean-provenance assumption "
168 "(typically by the safe-query rewrite, "
169 "provenance class 'boolean') and the evaluation is "
170 "unsound under this semiring. Re-run the query under "
171 "a more general provenance class, or pick a "
172 "Boolean-compatible semiring (boolean, boolexpr, "
174 }
else if(assumption ==
"absorptive") {
177 "The requested semiring is not absorptive; the "
178 "wrapped sub-circuit only represents the absorptive "
179 "quotient of a recursive query's provenance "
180 "(fixpoint truncation or compiled reachability "
181 "circuit), so its value is only defined for "
182 "absorptive semirings (probability, boolean, "
183 "formula-with-absorption, nonnegative tropical, "
184 "...). Counting and why-provenance of such a "
185 "recursion are genuinely infinite: a tuple derived "
186 "through itself gains a derivation per round, which "
187 "cyclic data does and so does a null-padded row that "
188 "re-derives itself or a projection onto constants, on "
214 "Unknown assumption marker '" + assumption +
"'");
223 "Comparison operator OID " +
236 if(provenance_mapping.find(c) == provenance_mapping.end()) {
244 const auto childValue = [&](
int i) ->
const typename S::value_type & {
245 return provenance_mapping.at(
getWires(u)[i]);
252 std::vector<typename S::value_type> childrenResult;
254 childrenResult.push_back(provenance_mapping.at(c));
256 childrenResult.erase(std::remove(std::begin(childrenResult), std::end(childrenResult),
semiring.zero()),
257 childrenResult.end());
258 provenance_mapping.emplace(u,
semiring.plus(childrenResult));
261 for(
const auto &c: childrenResult) {
268 provenance_mapping.emplace(u,
semiring.zero());
270 childrenResult.erase(std::remove(std::begin(childrenResult), std::end(childrenResult),
semiring.one()),
271 childrenResult.end());
272 provenance_mapping.emplace(u,
semiring.times(childrenResult));
275 if(childrenResult[0]==
semiring.zero() || childrenResult[0]==childrenResult[1])
276 provenance_mapping.emplace(u,
semiring.zero());
278 provenance_mapping.emplace(u,
semiring.monus(childrenResult[0], childrenResult[1]));
284 provenance_mapping.emplace(u,
semiring.delta(childValue(0)));
295 provenance_mapping.emplace(u, childValue(0));
302 provenance_mapping.emplace(u,
semiring.cmp(childValue(0), op, childValue(1)));
307 provenance_mapping.emplace(u,
semiring.semimod(childValue(0), childValue(1)));
316 std::vector<typename S::value_type> vec;
318 vec.push_back(provenance_mapping.at(c));
319 provenance_mapping.emplace(u,
semiring.agg(op, vec));
332 std::vector<typename S::value_type> vec;
334 vec.push_back(provenance_mapping.at(c));
335 provenance_mapping.emplace(u,
semiring.conditioned(vec));
351 const std::string key =
"L:";
352 std::size_t p = ex.find(key);
353 if(p != std::string::npos) {
354 std::size_t e = ex.find(
' ', p);
355 const std::string luid =
356 ex.substr(p + key.size(),
357 e == std::string::npos ? std::string::npos : e - p - key.size());
359 if(
getUUID(c) == luid) { lineage = c;
break; }
362 provenance_mapping.emplace(u, provenance_mapping.at(lineage));
364 provenance_mapping.emplace(u, childValue(0));
375 std::vector<typename S::value_type> vec;
377 vec.push_back(provenance_mapping.at(c));
378 provenance_mapping.emplace(u,
semiring.guarded_case(vec));
389 std::vector<typename S::value_type> params;
391 params.push_back(provenance_mapping.at(c));
401 "Arithmetic operator tag " +
404 std::vector<typename S::value_type> vec;
406 vec.push_back(provenance_mapping.at(c));
418 std::vector<double> probs;
419 std::vector<std::string> outcomes;
420 for(std::size_t i = 1; i < w.size(); ++i) {
421 probs.push_back(
getProb(w[i]));
424 provenance_mapping.emplace(
425 u,
semiring.categorical(childValue(0), probs, outcomes));
429 "gate_mixture must have exactly three children "
430 "[p_token, x_token, y_token]");
431 provenance_mapping.emplace(
432 u,
semiring.mixture(childValue(0), childValue(1), childValue(2)));
441 "gate_observe must have exactly one child (the observed leaf)");
442 provenance_mapping.emplace(u,
semiring.observe(childValue(0),
getExtra(u)));
453 return provenance_mapping.at(g);