\set ECHO none \pset format unaligned SET provsql.rv_mc_samples = 0; -- Natural Boolean-predicate conditioning: the right operand of | (and the -- prefix | argument) may be a Boolean combination of random_variable / -- aggregate comparisons, which the ProvSQL planner converts to a condition -- gate. So "X | (X > 3)" stands for "X | rv_cmp_gt(X, as_random(3))", and the -- same principle works for every carrier (uuid / random_variable / agg_token) -- and the prefix whole-tuple form. Parentheses around the predicate are -- required: a custom | binds tighter than >, so "X | X > 3" would parse as -- "(X | X) > 3". -- random_variable: truncation written naturally agrees with the gate form; -- compound AND predicates work (De Morgan via provenance_times / _plus). WITH r AS (SELECT normal(0,1) AS rv, uniform(0,10) AS u) SELECT (expected(r.rv | (r.rv > 3)) = expected(r.rv | rv_cmp_gt(r.rv, as_random(3)))) AS rv_predicate_matches, round(expected(r.u | (r.u > 3 AND r.u < 7))::numeric,6) AS rv_compound_mean FROM r; -- agg_token: condition an aggregate on a HAVING-style predicate. The rewriter -- must be on (it converts the predicate), so materialise the scalar result and -- read it back. E[SUM | SUM>25] = 30 (only the both-present world, SUM=30, -- qualifies); E[SUM] = 15 unconditionally. CREATE TABLE s(g int, x int, p float); INSERT INTO s VALUES (1,10,0.5),(1,20,0.5); SELECT add_provenance('s'); DO $$ BEGIN PERFORM set_prob(provenance(), p) FROM s; END $$; CREATE TABLE agg AS SELECT g, sum(x) AS sx FROM s GROUP BY g; CREATE TABLE agg_res AS SELECT expected(agg.sx | (agg.sx > 25)) AS e_cond, expected(agg.sx) AS e_uncond FROM agg; SET provsql.active = off; SELECT round(e_cond::numeric,4) AS agg_predicate, round(e_uncond::numeric,4) AS agg_uncond FROM agg_res; RESET provsql.active; -- prefix | (predicate): whole-tuple output conditioning on a Boolean event. -- The row's existence is independent of sensor>3, so P stays the row's .8. CREATE TABLE readings(id int, sensor random_variable, p float); INSERT INTO readings VALUES (1, normal(0,1), 0.8); SELECT add_provenance('readings'); DO $$ BEGIN PERFORM set_prob(provenance(), p) FROM readings; END $$; CREATE TABLE pc AS SELECT id, | (sensor > 3) FROM readings; SET provsql.active = off; SELECT id, get_gate_type(provsql) AS gate, round(probability_evaluate(provsql)::numeric,4) AS p_cond FROM pc ORDER BY id; RESET provsql.active; SELECT remove_provenance('s'); SELECT remove_provenance('readings'); DROP TABLE agg_res; DROP TABLE agg; DROP TABLE s; DROP TABLE pc; DROP TABLE readings; -- Mixed predicate: an ordinary (regular-column) comparison combined with a -- probabilistic one. The regular comparison becomes a deterministic -- indicator (gate_one / gate_zero) per the HAVING-provenance semantics, so -- "SUM(x) | (SUM(x) > 25 AND region = 'north')" conditions on SUM>25 when the -- group is in the north (indicator 1 -> E = 30) and on the impossible event -- otherwise. A PURELY regular predicate is rejected (it is an ordinary -- filter, not a conditioning event). CREATE TABLE sr(g int, region text, x int, p float); INSERT INTO sr VALUES (1,'north',10,0.5),(1,'north',20,0.5); SELECT add_provenance('sr'); DO $$ BEGIN PERFORM set_prob(provenance(), p) FROM sr; END $$; CREATE TABLE aggr AS SELECT g, region, sum(x) AS sx FROM sr GROUP BY g, region; CREATE TABLE mixed_res AS SELECT expected(aggr.sx | (aggr.sx > 25 AND aggr.region = 'north')) AS e_north FROM aggr; SET provsql.active = off; SELECT round(e_north::numeric,4) AS e_mixed_north FROM mixed_res; RESET provsql.active; -- Purely regular predicate: rejected with a clear message. SELECT expected(aggr.sx | (aggr.region = 'north')) FROM aggr; SELECT remove_provenance('sr'); DROP TABLE mixed_res; DROP TABLE aggr; DROP TABLE sr;