Note
Go to the end to download the full example code.
3. Probabilities under changing assumptions¶
Rain or a sprinkler makes the ground wet:
W = R ∨ S. Given wet ground, what is the probability of rain?
We build the events once, then evaluate them under two sets of independent
priors. A third variable, wind, is unconstrained by these events.
3.1. Exact fractions¶
Fraction comes from Python’s standard library. Each variable has a pair
of weights: false first, true second. For independent probabilities these
sum to one. In particular, the free wind variable contributes one.
In both scenarios below the evidence has positive probability, so
P(R | W) = P(R ∧ W) / P(W) is defined.
for rain_probability in [Fraction(1, 5), Fraction(3, 5)]:
priors = {1: rain_probability, 2: Fraction(1, 10), 3: Fraction(2, 5)}
weights = {variable: (1 - p, p) for variable, p in priors.items()}
wet_probability = wet.weighted_count(weights)
conditional = rain_and_wet.weighted_count(weights) / wet_probability
print(f"P(rain) = {rain_probability}, P(wet) = {wet_probability}")
print("P(rain | wet) =", conditional)
P(rain) = 1/5, P(wet) = 7/25
P(rain | wet) = 5/7
P(rain) = 3/5, P(wet) = 16/25
P(rain | wet) = 15/16
Both evaluations borrowed their circuits. No rebuilding or copying was needed when the priors changed. More generally, weights need not sum to one: unit weights recover the model count.
Models of wet: 6
3.2. Change observations¶
An evaluator caches values so changing an observation refreshes only affected
branches. It consumes wet; finish() returns the circuit when we are done.
The value with no rain is the joint probability P(W ∧ ¬R), without normalization.
P(wet and no rain) = 1/25
P(wet) = 16/25