File size: 1,798 Bytes
198bd6d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
import math


def _imports():
    try:
        from bayesian_langchain.smc import ParticleFilter, Proposal, SMCConfig
    except ImportError:
        from bayesian_langgraph.smc import ParticleFilter, Proposal, SMCConfig
    return ParticleFilter, Proposal, SMCConfig


def test_final_step_preserves_nonuniform_posterior_weights():
    ParticleFilter, Proposal, SMCConfig = _imports()
    pf = ParticleFilter(SMCConfig(n_particles=64, n_steps=1, ess_resample_fraction=0.99, seed=7))

    def propose(state, t):
        return [Proposal("good", 0.5), Proposal("bad", 0.5)]

    def transition(state, action, t):
        return action

    def log_target(prev, action, nxt, t):
        return 0.0 if action == "good" else math.log(1e-5)

    particles = pf.run(None, propose, transition, log_target)
    probs = [p.posterior for p in particles]
    assert abs(sum(probs) - 1.0) < 1e-12
    # If the old final-resampling bug returned, these would all be 1/N.
    assert max(probs) - min(probs) > 1e-3


def test_importance_weight_contains_inverse_proposal_probability():
    ParticleFilter, Proposal, SMCConfig = _imports()
    pf = ParticleFilter(SMCConfig(n_particles=256, n_steps=1, seed=11))

    def propose(state, t):
        return [Proposal("a", 0.9), Proposal("b", 0.1)]

    def transition(state, action, t):
        return action

    # Equal target mass for both actions. Importance correction should cancel
    # the 9:1 proposal imbalance in the weighted posterior, up to MC error.
    def log_target(prev, action, nxt, t):
        return math.log(0.5)

    particles = pf.run(None, propose, transition, log_target)
    mass = {"a": 0.0, "b": 0.0}
    for p in particles:
        mass[p.state] += p.posterior
    assert abs(mass["a"] - 0.5) < 0.15
    assert abs(mass["b"] - 0.5) < 0.15