Prereqs: ๐ Fritz 2020 (Markov categories, Bayesian inversion). ๐ Hedges 2018 (compositional games) helps but isn't required.
A Bayesian lens pairs a forward channel (prediction) with a backward channel (Bayesian update). Composing lenses gives you a system that predicts and then corrects โ active inference falls out as the equilibrium of a statistical game.
Lenses: forward and backward
A lens is a pair: a get (forward pass, observation) and a put (backward pass, update). In the Bayesian setting, get is a likelihood channel and put is the Bayesian inverse โ the posterior update given new evidence.
The backward channel is the Bayesian inverse: given a prior and an observation, compute the posterior. This isn't an arbitrary update โ it's the unique channel that makes the joint distribution factor correctly.
# Bayesian inversiondef bayes_update(prior, likelihood, evidence):
joint = {h: ph * likelihood(h)[evidence] for h, ph in prior.items()}
total = sum(joint.values())
return {h: p / total for h, p in joint.items()}
prior = {"fair": 0.5, "biased": 0.5}
def likelihood(h):
return {"heads": 0.5, "tails": 0.5} if h == "fair"else {"heads": 0.8, "tails": 0.2}
print(f"prior: {prior}")
print(f"after heads: {bayes_update(prior, likelihood, 'heads')}")
print(f"after tails: {bayes_update(prior, likelihood, 'tails')}")
Composing lenses
Two Bayesian lenses compose: the forward passes chain (predict through both stages), and the backward passes chain in reverse (update flows back). This is the categorical structure of lenses โ composition is well-defined and associative.
Scheme
; Composing lenses: forward chains, backward reverses; L1: A -> B, L2: B -> C; Composed: A -> C (forward), C -> A (backward)
(define (compose-lens L1 L2)
(let ((f1 (car L1)) (b1 (cadr L1))
(f2 (car L2)) (b2 (cadr L2)))
(list
; Forward: f2(f1(a))
(lambda (a) (f2 (f1 a)))
; Backward: b1(a, b2(f1(a), c))
(lambda (a c) (b1 a (b2 (f1 a) c))))))
(define L1 (list (lambda (x) (+ x 1))
(lambda (x obs) (- obs 1))))
(define L2 (list (lambda (x) (* x 2))
(lambda (x obs) (/ obs 2))))
(define L (compose-lens L1 L2))
(display "forward(3) = ") (display ((car L) 3)) (newline)
(display "backward(3, 10) = ") (display ((cadr L) 310))
; forward: (3+1)*2 = 8, backward: recovers via inverse
A statistical game has players that minimize variational free energy โ the gap between their model's predictions and the actual observations. The equilibrium of the game is active inference: each agent updates its beliefs to minimize surprise.
Scheme
; Free energy: surprise + complexity; F = -log P(observation | model) + KL(posterior || prior); At equilibrium, agents minimize F
(define (log2 x) (/ (log x) (log 2)))
(define (free-energy obs-prob kl-div)
(+ (- (log2 obs-prob)) kl-div))
; Good model: high observation probability, low divergence
(display "good model: F = ")
(display (free-energy 0.80.1)) (newline)
; Bad model: low observation probability, high divergence
(display "bad model: F = ")
(display (free-energy 0.12.0)) (newline)
; Active inference minimizes F by updating beliefs
(display "Agents update beliefs to reduce free energy.")
Python
importmathdef free_energy(obs_prob, kl_div):
return -math.log2(obs_prob) + kl_div
# Good model: high observation probability, low divergenceprint(f"good model: F = {free_energy(0.8, 0.1):.3f}")
# Bad model: low observation probability, high divergenceprint(f"bad model: F = {free_energy(0.1, 2.0):.3f}")
print("Agents update beliefs to reduce free energy.")
Notation reference
Paper
Scheme
Meaning
(f, fโ )
(make-lens fwd bwd)
Bayesian lens (forward, inverse)
fโ
(bayes-update ...)
Bayesian inverse channel
F
(free-energy ...)
Variational free energy
Lโ โ Lโ
(compose-lens L1 L2)
Lens composition
BayesLens(C)
; category of Bayesian lenses
Category with Bayesian backward passes
Neighbors
Other paper pages
๐ Fritz 2020 โ the Markov category where these lenses live
The Bayesian update examples use finite hypothesis spaces with explicit probability tables. Smithe works with Bayesian inversions in arbitrary Markov categories, where the backward channel is defined via a universal property (the disintegration). For example: the coin-bias update on this page shifts a point estimate by ยฑ0.1. In the paper, the backward channel is the exact Bayesian posterior computed via disintegration of the joint measure โ a construction that works over continuous parameter spaces and requires measure-theoretic conditioning. The predict-then-update structure is identical. The exactness of the inversion is not.
Every example is Simplified.
Ready for the real thing? Read the paper. Start at ยง3 for Bayesian lenses, ยง5 for statistical games and free energy.
Framework connection: The backward pass of a Bayesian lens corresponds to the Natural Framework's Consolidate stage โ the policy update that reads from persistent memory. (The Natural Framework)