feat: hold a leaf parameter fixed in the priors front-door (#752) - #761
Merged
Conversation
A plain value in a prior slot should pin a leaf parameter: substituted as a constant, never sampled, absent from VarInfo and the chain, yet present in the update'd distribution.
A plain value in a prior slot pins that leaf parameter: it is substituted as a constant and never sampled. The sampling models classify each slot, sampling a distribution via tilde and substituting a non-distribution value directly, so a fixed parameter never enters the VarInfo or the chain (no tilde, no point mass). This sidesteps the DynamicPPL guard that rejects a Dirac point mass under NUTS. build_priors gains a fix keyword (a nested NamedTuple keyed like the tree whose leaf values are plain constants) that writes the constants into the prior NamedTuple; it takes precedence over a priors override and is validated against the inventory. The same pin is reachable by editing a built prior with update(priors, path => (param = value,)), so fix composes with the override mechanism rather than forking it. chain_to_params/update/param_draws gain a fix keyword that fills the pinned constants back into the reconstructed distribution, since they are absent from the fitted chain.
seabbs-bot
merged commit Jun 26, 2026
bebf85e
into
integration/composed-stack
12 of 21 checks passed
Contributor
Try this Pull Request!Option 1: Julia Package ManagerOpen Julia and type: import Pkg
Pkg.activate(temp=true)
Pkg.add(url="https://github.com/EpiAware/CensoredDistributions.jl", rev="feat/fixed-param-752")
using CensoredDistributionsOption 2: Local CheckoutIf you have the repo locally: git checkout feat/fixed-param-752
julia --project=. -e "using Pkg; Pkg.instantiate()" |
Codecov Report❌ Patch coverage is
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 4 files with indirect coverage changes 🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #752.
Problem
The priors front-door samples every inventory parameter through
tilde_assume!!, and aDiracpoint mass is rejected by DynamicPPL'sdiscrete-distribution guard under NUTS. There was no way to hold one leaf
parameter fixed while fitting the others (e.g. fit a Gamma's shape while
pinning its scale).
API
A leaf parameter is held fixed by placing a plain value (not a
distribution) in its prior slot. The sampling models classify each slot:
a
Distributionis sampled viatilde_assume!!as before; anon-distribution value is substituted directly as a constant. A fixed
parameter therefore never enters the sampler (no tilde, no point mass), so
it is absent from the
VarInfoand the chain, while the fitted parametersflow exactly as today.
Two equivalent ways to set the pin, both extending the existing override
mechanism rather than forking it:
fixtakes precedence over apriorsoverride for the same parameter andis validated against the inventory (a typo errors rather than pinning
nothing silently).
Reading the fit back, the pinned constant is absent from the chain, so
chain_to_params/update(template, chain)/param_drawsgain afixkeyword that fills the constants back into the reconstructed distribution:
Composes with the override API
Yes. The pin lives in the same nested prior NamedTuple that
build_priors,the
priors=override, andupdate(priors, path => fields)alreadyproduce and edit.
fixis a convenience that writes plain values into thatstructure; the
update-by-path route reaches the identical result with nonew surface.
DynamicPPL note
No DynamicPPL limitation blocks the clean approach: because a fixed
parameter is substituted as a constant before any
~, the rejected-Diracpath is never taken. The guard that motivated #752 is sidestepped entirely.
Tests
Red/green TDD. New tests:
build_priors fix pins a parameter as a constant (#752)(unit):fixinserts a plain value, takes precedence over a
priorsoverride, matchesthe
update-by-path pin, and errors on an unknown parameter.fixed leaf parameter: held constant, absent from VarInfo(turing): thefixed scale is in the reconstructed leaf and absent from the
VarInfo,the free shape is sampled.
fixed leaf parameter: update from chain keeps the pin(turing): a realNUTS fit recovers the free shape (~3.0) with the scale pinned at 1.5; the
pinned value is absent from the chain yet reappears via
update(template, chain; fix = priors).Passing locally: the three new testitems and the
build_priorsunit test.The full
ComposedParametersModel.jlsuite is re-running locally toconfirm no regression; CI runs the whole suite (Turing + AD backends) on
this PR.
This was opened by a bot. Please ping @seabbs for any questions.