\set ECHO none \pset format unaligned -- Latent variables, discrete families: poisson(random_variable) and -- binomial(integer, random_variable) are parametric gate_rv leaves (the -- literal-parameter constructors still enumerate an exact categorical). -- They reuse the whole latent machinery: per-draw sampling, the Poisson / -- Binomial pmf as the observe likelihood weight, and the affine-mean fast -- path (Poisson mean = lambda). Discrete-likelihood posteriors (Gamma- -- Poisson, Beta-Binomial) are conjugate, so the IS posterior matches the -- closed form. SET search_path TO provsql, public; SET provsql.monte_carlo_seed = 20260706; SET provsql.rv_mc_samples = 400000; SET provsql.ess_warn_fraction = 0; -- --------------------------------------------------------------------- -- Forward compound moments. -- E[Poisson(Lambda)] = E[Lambda] (affine mean, exact) -- Var[Poisson(Lambda)] = E[Lambda] + Var[Lambda] (law of total variance) -- E[Binomial(n, P)] = n E[P] -- --------------------------------------------------------------------- -- E[Poisson(Gamma(2,1))] = E[Gamma(2,1)] = 2, EXACT (no MC). SET provsql.rv_mc_samples = 0; SELECT expected(poisson(gamma(2, 1))) = 2.0 AS poisson_mean_exact; SET provsql.rv_mc_samples = 400000; -- Var[Poisson(Uniform(4,6))] = 5 + (6-4)^2/12 = 5.3333. SELECT abs(variance(poisson(uniform(4, 6))) - 5.3333) < 0.15 AS poisson_var_total; -- E[Binomial(50, Uniform(0,1))] = 50 * 0.5 = 25. SELECT abs(expected(binomial(50, uniform(0, 1))) - 25.0) < 0.3 AS binomial_mean; -- --------------------------------------------------------------------- -- Gamma-Poisson conjugacy. Prior R ~ Gamma(shape 2, rate 1); counts -- x_i ~ Poisson(R); data {3, 5, 4} (n = 3, sum = 12). Posterior -- R ~ Gamma(2 + 12, 1 + 3) = Gamma(14, 4): mean = 3.5, var = 14/16 = 0.875. -- --------------------------------------------------------------------- DO $$ DECLARE r random_variable := gamma(2, 1); ev uuid; BEGIN SELECT and_agg(observe(poisson(r), x)) INTO ev FROM (VALUES (3.0::float8), (5.0), (4.0)) AS t(x); RAISE NOTICE 'gamma_poisson_mean: %', (abs(expected(r, ev) - 3.5) < 0.1); RAISE NOTICE 'gamma_poisson_var: %', (abs(variance(r, ev) - 0.875) < 0.1); END $$; -- --------------------------------------------------------------------- -- Beta-Binomial conjugacy. Prior p ~ Beta(2, 2); successes k_i ~ -- Binomial(10, p); data {7, 8, 6} (sum k = 21, sum failures = 9). Posterior -- p ~ Beta(2 + 21, 2 + 9) = Beta(23, 11): mean = 23/34 = 0.6765. -- --------------------------------------------------------------------- DO $$ DECLARE p random_variable := beta(2, 2); ev uuid; BEGIN SELECT and_agg(observe(binomial(10, p), k)) INTO ev FROM (VALUES (7.0::float8), (8.0), (6.0)) AS t(k); RAISE NOTICE 'beta_binomial_mean: %', (abs(expected(p, ev) - 0.6765) < 0.02); END $$; -- --------------------------------------------------------------------- -- Beta-Geometric conjugacy. Prior p ~ Beta(2, 2); trials x_i ~ Geometric(p) -- on {1, 2, ...}; data {2, 3, 4} (n = 3, sum = 9). Posterior -- p ~ Beta(2 + n, 2 + sum - n) = Beta(5, 8): mean = 5/13 = 0.3846. -- --------------------------------------------------------------------- DO $$ DECLARE p random_variable := beta(2, 2); ev uuid; BEGIN SELECT and_agg(observe(geometric(p), x)) INTO ev FROM (VALUES (2.0::float8), (3.0), (4.0)) AS t(x); RAISE NOTICE 'beta_geometric_mean: %', (abs(expected(p, ev) - 0.3846) < 0.02); END $$; -- --------------------------------------------------------------------- -- Beta-NegativeBinomial conjugacy. Prior p ~ Beta(2, 2); failures k_i ~ -- NegBinom(r = 5, p) on {0, 1, ...}; data {4, 6, 5} (n = 3, sum = 15). -- Posterior p ~ Beta(2 + n*r, 2 + sum) = Beta(17, 17): mean = 0.5. -- --------------------------------------------------------------------- DO $$ DECLARE p random_variable := beta(2, 2); ev uuid; BEGIN SELECT and_agg(observe(negative_binomial(5, p), k)) INTO ev FROM (VALUES (4.0::float8), (6.0), (5.0)) AS t(k); RAISE NOTICE 'beta_negbinom_mean: %', (abs(expected(p, ev) - 0.5) < 0.02); END $$; -- --------------------------------------------------------------------- -- Discrete point-event conditioning: a point event X = c on a discrete leaf -- carries positive mass, so it is FEASIBLE (a continuous X = c is measure- -- zero and folds away). The natural equality form X | (Y = k) is the -- internal form of observe(Y, k) and gives the same posterior -- even under -- simplify_on_load, which must not fold the discrete equality to zero. -- --------------------------------------------------------------------- SET provsql.rv_mc_samples = 500000; DO $$ DECLARE r random_variable := gamma(2, 1); via_observe double precision; BEGIN via_observe := expected(r, observe(poisson(3 * r), 5)); RAISE NOTICE 'discrete_equality_matches_observe: %', (abs(expected(r | (poisson(3 * r) = 5)) - via_observe) < 0.05); END $$; -- --------------------------------------------------------------------- -- Parameter-domain guard: a rate/probability prior that leaves the family's -- domain raises rather than silently truncating. -- --------------------------------------------------------------------- -- Poisson rate that can draw <= 0 (variance samples the rate). DO $$ BEGIN PERFORM variance(poisson(normal(0, 3))); RAISE NOTICE 'poisson_rate_guard: f'; EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'poisson_rate_guard: %', (SQLERRM LIKE '%outside the family''s domain%'); END $$; -- Binomial probability that can leave [0, 1]. DO $$ BEGIN PERFORM expected(binomial(10, normal(0.5, 1))); RAISE NOTICE 'binomial_prob_guard: f'; EXCEPTION WHEN OTHERS THEN RAISE NOTICE 'binomial_prob_guard: %', (SQLERRM LIKE '%outside the family''s domain%'); END $$;