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 + d2the correct way to making the “deterministic” sum of the two diced1andd2? 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,PGorSMCforcesd1andd2.
A variant of the above model is the following where s is observed via the model parameter sdirectly (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.