Probabilistic programs as traced computations.
sample, observe and factor publish savepoints (sites
:inference/choose and :inference/factor), so a probabilistic program is
run and replayed by spindel.trace like any other computation. This
namespace adds what is specific to inference and nothing else: a policy that
scores, pure functions over scored traces, and Metropolis-Hastings as replay
plus an accept step.
Every entry's :note carries
:dist the site's distribution (nil for a factor) :log-prob log density of the entry's value under :dist, for EVERY site, sampled ones included (a factor's weight) :log-proposal log density under whatever drew the value; absent when the value was not drawn (observed, constrained, kept) :observed? :constrained? :kept? :symmetric? :factor?
A deterministic site is recorded with {:deterministic? true} only; it is
not among entries, so it neither scores nor moves.
and the world accumulates the importance weight at [:inference :log-weight]: log p of what was observed, constrained or factored, and
log p - log q of what a proposal drew. A policy writes it to the world it
is about to resume, so the weight of a fork starts from the weight at its
site.
Probabilistic programs as traced computations.
`sample`, `observe` and `factor` publish savepoints (sites
`:inference/choose` and `:inference/factor`), so a probabilistic program is
run and replayed by `spindel.trace` like any other computation. This
namespace adds what is specific to inference and nothing else: a policy that
scores, pure functions over scored traces, and Metropolis-Hastings as replay
plus an accept step.
Every entry's `:note` carries
:dist the site's distribution (nil for a factor)
:log-prob log density of the entry's value under :dist, for EVERY
site, sampled ones included (a factor's weight)
:log-proposal log density under whatever drew the value; absent when the
value was not drawn (observed, constrained, kept)
:observed? :constrained? :kept? :symmetric? :factor?
A `deterministic` site is recorded with `{:deterministic? true}` only; it is
not among `entries`, so it neither scores nor moves.
and the world accumulates the importance weight at `[:inference
:log-weight]`: `log p` of what was observed, constrained or factored, and
`log p - log q` of what a proposal drew. A policy writes it to the world it
is about to resume, so the weight of a fork starts from the weight at its
site.(anchor? sp)Whether a site is worth an anchor: only a site a move can start from. An observe or a factor is never replayed from, and an anchor is a forked world. Once a keyed region has been entered, sites take no anchors: children can still be in flight, and old downstream checkpoints would be invalidated by later key updates. Independent keys use reexecute; a broader change needs a valid upstream anchor. This also covers nested child spins. Pass as :anchor? to trace/run and trace/replay.
Whether a site is worth an anchor: only a site a move can start from. An observe or a factor is never replayed from, and an anchor is a forked world. Once a keyed region has been entered, sites take no anchors: children can still be in flight, and old downstream checkpoints would be invalidated by later key updates. Independent keys use reexecute; a broader change needs a valid upstream anchor. This also covers nested child spins. Pass as :anchor? to trace/run and trace/replay.
(barrier-site? sp)Whether a savepoint is where SMC parks a particle: an observation, a
stream site, or a factor marked :barrier.
Whether a savepoint is where SMC parks a particle: an observation, a stream site, or a factor marked `:barrier`.
(changed-addresses old new)Addresses rewritten, added or removed. Released Spindel 0.1.140 does not report :trace/removed, so deletion accounting conservatively scans keys.
Addresses rewritten, added or removed. Released Spindel 0.1.140 does not report :trace/removed, so deletion accounting conservatively scans keys.
(choices trace){address value} of the sample sites of trace.
{address value} of the sample sites of `trace`.
(copy-complete t opts)Fork a settled end-world without re-running its effects. The caller owns shared anchors and must keep every live population reachable until release.
Fork a settled end-world without re-running its effects. The caller owns shared anchors and must keep every live population reachable until release.
(entries trace)The inference entries of trace in program order, each with its :address.
The inference entries of `trace` in program order, each with its :address.
(latent-addresses trace)Addresses of the sample sites of trace that inference may move.
Addresses of the sample sites of `trace` that inference may move.
(latent-count trace)How many latent sites trace has.
How many latent sites `trace` has.
(latent-index trace){:addresses [address …] :position {address i}} of the latent sites of
trace: carried by a trace an incremental move made (patched with what
the move changed), built from the entries otherwise.
{:addresses [address …] :position {address i}} of the latent sites of
`trace`: carried by a trace an incremental move made (patched with what
the move changed), built from the entries otherwise.(latent? entry)Whether a trace entry is a sample site inference may move: not observed, not constrained.
Whether a trace entry is a sample site inference may move: not observed, not constrained.
(legacy-trace trace)trace in the legacy shape of a particle's trace ([:inference :trace]):
{address {:value :distribution :log-prob :observed?}}, and
{address {:value :deterministic? true}} for deterministic sites.
`trace` in the legacy shape of a particle's trace (`[:inference :trace]`):
{address {:value :distribution :log-prob :observed?}}, and
{address {:value :deterministic? true}} for deterministic sites.(log-joint trace)log p(choices, observations) of trace: the sum of every entry's
:log-prob.
log p(choices, observations) of `trace`: the sum of every entry's :log-prob.
(log-weight trace)The importance weight the world of trace accumulated.
The importance weight the world of `trace` accumulated.
(mh-chain trace n)(mh-chain trace
n
{:keys [on-step first-iteration iteration-stride]
move :step
:or {move mh-step iteration-stride 1}
:as opts})n Metropolis-Hastings moves from trace; opts as for mh-step.
Returns a CPS operation resolving {:trace final :moves m :accepted k}: of
the m moves made, k were accepted. :on-step (fn [step-result]) sees every
step. :step (fn [trace opts]) -> CPS resolving a step result replaces
mh-step (e.g. foerster.hmc/within-gibbs); a step that makes several
moves reports :moves and :accepted-moves, otherwise it is one move,
accepted when :accepted?. A move's randomness is keyed by its number in
the trace's world, so the moves made from one world need distinct numbers:
:iteration-stride (default 1) reserves that many RNG indices per outer
iteration, for composed transitions. They are numbered from
:first-iteration, or — when it is not given —
from a counter the world keeps, so calling mh-chain again on the same
trace (after a rejection, the world is the same) draws afresh.
`n` Metropolis-Hastings moves from `trace`; `opts` as for `mh-step`.
Returns a CPS operation resolving {:trace final :moves m :accepted k}: of
the m moves made, k were accepted. `:on-step` (fn [step-result]) sees every
step. `:step` (fn [trace opts]) -> CPS resolving a step result replaces
`mh-step` (e.g. `foerster.hmc/within-gibbs`); a step that makes several
moves reports `:moves` and `:accepted-moves`, otherwise it is one move,
accepted when `:accepted?`. A move's randomness is keyed by its number in
the trace's world, so the moves made from one world need distinct numbers:
:iteration-stride (default 1) reserves that many RNG indices per outer
iteration, for composed transitions. They are numbered from
`:first-iteration`, or — when it is not given —
from a counter the world keeps, so calling `mh-chain` again on the same
trace (after a rejection, the world is the same) draws afresh.(mh-log-ratio old new log-selection)(mh-log-ratio old new log-selection from)(mh-log-ratio old new log-selection from score)(mh-log-ratio old new log-selection from score changed)Log acceptance ratio of moving from old to new, where new is old
replayed from its earliest target with kept values elsewhere.
log a = [log p(new) - log p(old)] + [log q(old | new) - log q(new | old)] + [log s(targets | new) - log s(targets | old)]
q(new | old) is the density of everything new drew afresh; q(old | new) is
the density of everything of old that new did not keep, which the
reverse move would have to draw (from the prior, hence its :log-prob, or a
block's :sample density). A
symmetric move cancels on both sides. s is the probability of selecting the
targets, log-selection; it differs between the traces when the move
changed how many sites there are to select from.
A kept value that fell out of its site's support is drawn again
(:redrawn?). That is reversible only if the reverse move would redraw there
too, i.e. if the new value is outside the OLD support; otherwise the reverse
keeps it, the old state cannot be reached back, and the move is impossible.
Entries upstream of the replayed address are the SAME entries in both
traces and cancel everywhere. That relies on a fork sharing the notes of its
source by reference, which holds for the in-process worlds a session forks
and would not survive a serialized trace. With from, the replayed
address, only the entries from it on are compared: the ratio is the same,
and it costs the replayed suffix instead of the whole trace. score
(fn [entry]) is an entry's log target (default its :log-prob), e.g.
tempered-score. With changed, the addresses an update rewrote, added
or removed (changed-addresses), only those are compared: every other
entry is the same in both and cancels.
Log acceptance ratio of moving from `old` to `new`, where `new` is `old`
replayed from its earliest target with kept values elsewhere.
log a = [log p(new) - log p(old)]
+ [log q(old | new) - log q(new | old)]
+ [log s(targets | new) - log s(targets | old)]
q(new | old) is the density of everything `new` drew afresh; q(old | new) is
the density of everything of `old` that `new` did not keep, which the
reverse move would have to draw (from the prior, hence its :log-prob, or a
block's :sample density). A
symmetric move cancels on both sides. s is the probability of selecting the
targets, `log-selection`; it differs between the traces when the move
changed how many sites there are to select from.
A kept value that fell out of its site's support is drawn again
(`:redrawn?`). That is reversible only if the reverse move would redraw there
too, i.e. if the new value is outside the OLD support; otherwise the reverse
keeps it, the old state cannot be reached back, and the move is impossible.
Entries upstream of the replayed address are the SAME entries in both
traces and cancel everywhere. That relies on a fork sharing the notes of its
source by reference, which holds for the in-process worlds a session forks
and would not survive a serialized trace. With `from`, the replayed
address, only the entries from it on are compared: the ratio is the same,
and it costs the replayed suffix instead of the whole trace. `score`
(fn [entry]) is an entry's log target (default its :log-prob), e.g.
`tempered-score`. With `changed`, the addresses an update rewrote, added
or removed (`changed-addresses`), only those are compared: every other
entry is the same in both and cancels.(mh-step t)(mh-step t
{:keys [select propose iteration constraints policy-options temperature
keep-old? shared-anchors? until]
:or {select uniform-site propose prior-proposal iteration 0}
:as opts})One MH move using keyed re-execution for complete independent regions and anchored replay otherwise. :select / :propose / :constraints / :temperature retain their usual meaning. :keep-old? and :shared-anchors? are ownership policies; :until denotes an anchored replay frontier.
One MH move using keyed re-execution for complete independent regions and anchored replay otherwise. :select / :propose / :constraints / :temperature retain their usual meaning. :keep-old? and :shared-anchors? are ownership policies; :until denotes an anchored replay frontier.
(policy)(policy {fallback :else :as opts})The scoring policy.
Options:
:constraints {address value} fix those sample sites; their density enters
the weight
:keep? reuse the value a sample site had in the replayed trace,
rescored under the site's distribution NOW
:draw (fn [sp old-entry]) -> nil (not my site) or
{:value v :log-proposal lq}, or {:value v :symmetric? true}
for a symmetric move around the old value
:interventions {selector transform}: a selected sample site takes
{:do v} (that value, no score), {:policy (fn [choices])}
(a value from the choices made so far), {:dist d} (a new
mechanism) or {:shift δ} (the old one moved by δ). A key
that is not a selector (spindel.select) is an address; the
world's [:inference :interventions] (intervene!) apply too
Mechanism replacements preserve factual noise by default;
:coupling :fresh explicitly introduces independent noise.
:noise {address u}: the site takes its mechanism's value for u
(foerster.mechanism), observed sites included — a
counterfactual world. Sites without noise are marked
:unaligned?
:strict? with :noise, refuse a site without compatible factual noise;
otherwise draw fresh, including observed sites
:simulate-observed? true: observed sites draw a fresh value from their
distribution instead of scoring the data (predictive runs:
with :constraints holding a posterior draw's latents)
:temperature β in [0, 1]: observations and factors count β·log p — the
target p(x)·L(x)^β of tempered SMC (foerster.tempering).
Their notes keep :log-lik, the untempered log p
:init? start a sample site at its :init option. Only for the
first state of a Markov chain, which may be anything; an
:init value is not a draw, so it has no place in a move or
in a weighted sample.
:else policy for every other site (default: its payload)
With no options every sample site is drawn from its prior: forward simulation, likelihood weighting.
Every choose entry's note records :barrier, its barrier index (see
barrier-site?); policy-options recovers the options.
The scoring policy.
Options:
:constraints {address value} fix those sample sites; their density enters
the weight
:keep? reuse the value a sample site had in the replayed trace,
rescored under the site's distribution NOW
:draw (fn [sp old-entry]) -> nil (not my site) or
{:value v :log-proposal lq}, or {:value v :symmetric? true}
for a symmetric move around the old value
:interventions {selector transform}: a selected sample site takes
`{:do v}` (that value, no score), `{:policy (fn [choices])}`
(a value from the choices made so far), `{:dist d}` (a new
mechanism) or `{:shift δ}` (the old one moved by δ). A key
that is not a selector (`spindel.select`) is an address; the
world's `[:inference :interventions]` (`intervene!`) apply too
Mechanism replacements preserve factual noise by default;
:coupling :fresh explicitly introduces independent noise.
:noise {address u}: the site takes its mechanism's value for u
(`foerster.mechanism`), observed sites included — a
counterfactual world. Sites without noise are marked
`:unaligned?`
:strict? with :noise, refuse a site without compatible factual noise;
otherwise draw fresh, including observed sites
:simulate-observed? true: observed sites draw a fresh value from their
distribution instead of scoring the data (predictive runs:
with `:constraints` holding a posterior draw's latents)
:temperature β in [0, 1]: observations and factors count β·log p — the
target p(x)·L(x)^β of tempered SMC (`foerster.tempering`).
Their notes keep `:log-lik`, the untempered log p
:init? start a sample site at its `:init` option. Only for the
first state of a Markov chain, which may be anything; an
`:init` value is not a draw, so it has no place in a move or
in a weighted sample.
:else policy for every other site (default: its payload)
With no options every sample site is drawn from its prior: forward
simulation, likelihood weighting.
Every choose entry's note records `:barrier`, its barrier index (see
`barrier-site?`); `policy-options` recovers the options.(policy-options policy)The options a policy was made from, or nil for another function.
The options a `policy` was made from, or nil for another function.
(prior-proposal sp _old-entry)Propose a fresh draw from a target site's own distribution.
Propose a fresh draw from a target site's own distribution.
(random-walk-proposal step-size)A symmetric Gaussian step of step-size around a real-valued target's
old value. A target whose law is not continuous (a boolean, an integer
count, a vector) has no such step; it gets a prior proposal.
A symmetric Gaussian step of `step-size` around a real-valued target's old value. A target whose law is not continuous (a boolean, an integer count, a vector) has no such step; it gets a prior proposal.
(reexecute t targets move opts)Rewrite selected sites through one execution interface. Complete independent keyed regions re-run their owning keys; other moves replay from the latest valid preceding anchor. Incremental parent-side inference effects and keyed streaming frontiers are refused unless safe prefix replay is available. Result metadata ::changed / ::restart describes the score delta to compare.
Rewrite selected sites through one execution interface. Complete independent keyed regions re-run their owning keys; other moves replay from the latest valid preceding anchor. Incremental parent-side inference effects and keyed streaming frontiers are refused unless safe prefix replay is available. Result metadata ::changed / ::restart describes the score delta to compare.
(target-temperature opts)Effective target beta: explicit context, then policy options, then one.
Effective target beta: explicit context, then policy options, then one.
(tempered-score beta)The log target of a trace entry at temperature beta, for entries recorded
under any temperature: observations and factors by their :log-lik, a
site drawn from its own draw density (a block's :sample) by that density
plus β times the rest of its target (see decide-choose).
The log target of a trace entry at temperature `beta`, for entries recorded under any temperature: observations and factors by their `:log-lik`, a site drawn from its own draw density (a block's :sample) by that density plus β times the rest of its target (see `decide-choose`).
(uniform-site trace _iteration)Select one latent site uniformly. A selection is {:targets #{address} :log-selection (fn [trace])}.
Select one latent site uniformly. A selection is
{:targets #{address} :log-selection (fn [trace])}.(update-gibbs t address)(update-gibbs t
address
{:keys [iteration constraints policy-options keep-old?]
:as opts
:or {iteration 0}})Exact finite-support Gibbs on complete traces with fixed site structure. Every other latent must stay fixed with no auxiliary redraws. Candidates violating this contract are refused; they are not an approximate Gibbs move. :temperature, target policy and ownership follow mh-step.
Exact finite-support Gibbs on complete traces with fixed site structure. Every other latent must stay fixed with no auxiliary redraws. Candidates violating this contract are refused; they are not an approximate Gibbs move. :temperature, target policy and ownership follow mh-step.
(update-step t)(update-step t opts)Incremental-aware MH, also used by the ordinary shared transition path.
Incremental-aware MH, also used by the ordinary shared transition path.
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |