I’m (still) a Turing beginner and tries to build some simple models (porting my WebPPL models). I now wonder how observing a sum of two (DiscreteUniform) random variables works, i.e. to force the sum to a specific value.
Here’s a simple model which sums the value of two dice:
@model two_dice(ss) = begin
d1 ~ DiscreteUniform(1, 6) # die 1
d2 ~ DiscreteUniform(1, 6) # die 2
s ~ DiscreteUniform(2, 12) # sum of d1+d2
s = d1 + d2
# Force s to be the parameter ss
s == ss || begin Turing.@addlogprob! -Inf; return end
end
# Now we observe that the sum is 2
model = two_dice(2)
num_chains = 1
chains = sample(model, MH(), MCMCThreads(), 10000, num_chains)
display(chains)
This model works, kind of: The display of chains
is:
Chains MCMC chain (10000×4×1 Array{Float64,3}):
Iterations = 1:10000
Thinning interval = 1
Chains = 1
Samples per chain = 10000
parameters = d1, d2, s
internals = lp
Summary Statistics
parameters mean std naive_se mcse ess rhat
Symbol Float64 Float64 Float64 Float64 Float64 Float64
d1 1.0032 0.0799 0.0008 0.0032 574.4010 1.0015
d2 1.0064 0.1599 0.0016 0.0064 574.4010 1.0015
s 6.9814 3.1706 0.0317 0.2331 145.6114 1.0078
Quantiles
parameters 2.5% 25.0% 50.0% 75.0% 97.5%
Symbol Float64 Float64 Float64 Float64 Float64
d1 1.0000 1.0000 1.0000 1.0000 1.0000
d2 1.0000 1.0000 1.0000 1.0000 1.0000
s 2.0000 4.0000 7.0000 10.0000 12.0000
I.e. both d1
and d2
are (correctly) forced to be 1, but s
is all over the place (values in 2…12). I had assumed that s
should be forced to be 2.
Note that this only works with MH()
; what I can see none of the other samplers forces d1
and d2
to 1.
Here are my questions:
- Is
s = d1 + d2
the correct way to making the “deterministic” sum of the two diced1
andd2
? Or are there better way to do this? - Is the code
s == ss || begin Turing.@addlogprob! -Inf; return end
the best (or even good) way of observing (forcing) the sums
? - Does it make sense that only MH() can handle these kind of problem: neither
IS
,PG
orSMC
forcesd1
andd2
.
A variant of the above model is the following where s
is observed via the model parameter s
directly (i.e. without any use of @addlogprob! via the paramter ss
):
@model two_dice(s) = begin
d1 ~ DiscreteUniform(1, 6)
d2 ~ DiscreteUniform(1, 6)
s ~ DiscreteUniform(2, 12)
# Observe the parameter directly
s = d1 + d2
end
model = two_dice(2)
# ...
This was actually the first approach I tried, but this don’t seems to connect s
with the input value (here 2) at all: both d1
and d2
are all even distributed in 1…6 (s
is not available since it’s an observed variable).
Related: I have probably been a little spoiled by some other PPLs I’ve tested (such as WebPPL, BLOG, and PSI) which all have some kind of explicit observe
function that seems to do the same thing as the code in the first model i.e. adding -Inf to the logprob. I tried to make an @observe
macro (or observe
function) for this but didn’t succeed. It would be nice if such a macro could be supported.
I might very well have missed some obvious thing here, but I could no find discussions about this in the excellent Turing documentation.