Skip to content

Commit 2c62136

Browse files
committed
Add goal for beta-binomial observation model
1 parent 0a8cc00 commit 2c62136

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

aemcmc/conjugates.py

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import aesara.tensor as at
2+
from etuples import etuple, etuplize
3+
from kanren.facts import Relation, fact
4+
from unification import var
5+
6+
conjugate = Relation("conjugate")
7+
8+
9+
def _create_beta_binomial_goal():
10+
r"""Produce a goal that represents the application of Bayes theorem
11+
for a beta prior with a binomial observation model.
12+
13+
.. math::
14+
15+
\begin{align*}
16+
p &\sim \operatorname{Beta}\left(\alpha, \beta\right)\\
17+
y &\sim \operatorname{Binomial}\left(n, p\right)
18+
\end{align*}
19+
20+
If we observe :math:`y=Y`, then :math:`p` follows a beta distribution:
21+
22+
.. math::
23+
24+
p \sim \operatorname{Beta}\left(\alpha + Y, \beta + n - Y\right)
25+
26+
"""
27+
28+
# Beta-binomial observation model
29+
alpha_lv, beta_lv = var(), var()
30+
p_srng_lv = var()
31+
p_size_lv = var()
32+
p_type_idx_lv = var()
33+
p_lv = etuple(
34+
etuplize(at.random.beta), p_srng_lv, p_size_lv, p_type_idx_lv, alpha_lv, beta_lv
35+
)
36+
n_lv = var()
37+
Y_lv = etuple(etuplize(at.random.binomial), var(), var(), var(), n_lv, p_lv)
38+
39+
y_vv = var() # observation
40+
41+
# Posterior distribution for p
42+
new_alpha_lv = etuple(etuplize(at.add), alpha_lv, y_vv)
43+
new_beta_lv = etuple(
44+
etuplize(at.add), beta_lv, n_lv, etuple(etuplize(at.neg), y_vv)
45+
)
46+
p_posterior_lv = etuple(
47+
etuplize(at.random.beta),
48+
p_srng_lv,
49+
p_size_lv,
50+
p_type_idx_lv,
51+
new_alpha_lv,
52+
new_beta_lv,
53+
)
54+
55+
return (Y_lv, y_vv, p_posterior_lv)
56+
57+
58+
model, observation, posterior = _create_beta_binomial_goal()
59+
fact(conjugate, (model, observation), posterior)

tests/test_conjugates.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import aesara.tensor as at
2+
from aesara.tensor.random import RandomStream
3+
from kanren import run
4+
from kanren.graph import walko
5+
from unification import var
6+
7+
from aemcmc.conjugates import conjugate
8+
9+
10+
def test_beta_binomial_conjugate():
11+
"""Test that we can produce the closed-form posterior for
12+
the binomial observation model with a beta prior.
13+
14+
"""
15+
16+
srng = RandomStream(0)
17+
18+
alpha = at.scalar("alpha")
19+
beta = at.scalar("alpha")
20+
p = srng.beta(alpha, beta, name="p")
21+
22+
n = at.iscalar("n")
23+
Y_rv = srng.binomial(n, p)
24+
y_vv = Y_rv.clone()
25+
26+
q_lv = var()
27+
(posterior_expr,) = run(1, q_lv, walko(conjugate, (Y_rv, y_vv), q_lv))
28+
posterior_expr.evaled_obj

0 commit comments

Comments
 (0)