PyBNF priors (pybnf.priors)¶
The pybnf.priors package holds PyBNF’s prior distributions. A free
parameter’s prior is one distribution family combined with one scale (see the
Prior, Distribution Family, and Parameter Scale entries in
CONTEXT.md): the family is evaluated entirely in the sampling space u,
and the owning FreeParameter holds the scale and applies the theta <-> u
transform around it.
The package contains sixteen distribution families – normal, uniform,
laplace, cauchy, gamma, exponential, chisquare, rayleigh,
half_normal, half_cauchy, beta, inv_gamma, weibull,
gumbel, logistic, and student_t – one small module per family. Each
is a Prior subclass of the same shape: it
self-registers with @register_prior_family, declares its field_names and
support, and provides a build classmethod plus a hand-written logpdf_jax.
Because the leaves are uniform, this page documents the package facade and the
shared infrastructure rather than enumerating all sixteen; the user-facing
catalog – which *_var keyword names each family, and which take reflecting
bounds – is in Priors and Parameter Initialization.
Package facade¶
The priors package: Prior = distribution family x scale (ADR-0010).
A free parameter’s prior is one Prior family (in family.py files,
self-registered via @register_prior_family) combined with one Scale
(LINEAR/LOG10). Importing this package fires the family decorators,
populating PRIOR_FAMILY_REGISTRY; from that registry we derive
PRIOR_KEYWORD_MAP – the single source of truth mapping a legacy *_var
config keyword to its (family_cls, scale) pair, consumed by both
config._load_variables and parse.py’s grammar.
The keyword naming is regular: a family with base b yields {b}_var
(linear) and log{b}_var (log10). var/logvar are the two static
no-prior keywords (Simplex start points), mapped to NoPrior.
- class pybnf.priors.Bijector[source]¶
A monotone unconstraining map
u = b(z)fromRonto a prior’s support.to_constrainedisb(z -> u);to_unconstrainedisb^{-1}(u -> z, used once to seed NUTS from the latin-hypercube start point);logdetis the change-of-variables Jacobianlog|b'(z)|added to the HMC target. The*_jaxpeers are the JAX-traceable forms the differentiable log-density uses.- to_constrained_jax(z)[source]¶
JAX-traceable
to_constrained()(the differentiable target).
- class pybnf.priors.FrozenPrior[source]¶
A
Priorbacked entirely by ascipy.statsfrozen distribution in the sampling spaceu(ADR-0010).Every location/scale/shape family (Normal, Laplace, Cauchy, Gamma, Exponential, ChiSquare, Rayleigh) has the same density/sampling/inverse-CDF/support shape – a thin delegation to its frozen distribution – so it lives here once. A subclass sets
self.frozenin__init__(andhas_bounded_supportas a class attribute) and provides the family-specificbuildclassmethod.NoPrior(no distribution) andUniform(a custom latin-hypercubeppf) do not use this base.
- class pybnf.priors.Linear[source]¶
-
- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
- class pybnf.priors.Ln[source]¶
-
- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
- class pybnf.priors.Log10[source]¶
-
- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
- class pybnf.priors.NoPrior[source]¶
The absence of a prior: a
var/logvarSimplex start point.Contributes nothing to the log prior, cannot be sampled, and has no support. It still pairs with a
Scale(logvarisLog10); the scale lives on theFreeParameter, not here.- classmethod build(p1, p2, scale, p3=None)[source]¶
Factory matching the family
buildsignature;p1/p2/p3/scaleare ignored – a no-prior parameter carries only a start value.
- field_names = ()¶
The config field names for the family’s distribution parameters, in
build()order – the new-eraparameter:record names each one (ADR-0043), so a positionalp1 p2becomesmean: .. , sd: ... Concrete families override; the length must matchn_params(the record buildsp1/p2/p3from the first three).
- frozen = None¶
The underlying scipy frozen distribution, or
None.
- has_bounded_support = False¶
Whether the family’s support is finite – drives reflecting-bounds eligibility and latin-hypercube participation.
Uniformoverrides.
- has_prior = False¶
Whether the family has a proper distribution (
Falseonly forNoPrior).
- logpdf_jax(u)[source]¶
A no-prior carrier contributes
0to the HMC target (ADR-0059), the JAX peer oflogpdf(). Returned as a JAX scalar so it sums cleanly with the family logpdfs without forcing a host/device transfer.
- class pybnf.priors.Prior[source]¶
A distribution family operating in the sampling space
u.Subclasses expose
logpdf/rvs/ppfinuand report theirsupport(inu) andhas_bounded_support.frozenis the underlyingscipy.statsfrozen distribution (orNoneforNoPrior), surfaced forFreeParameter._distributionback-compat.- field_names = ('p1', 'p2')¶
The config field names for the family’s distribution parameters, in
build()order – the new-eraparameter:record names each one (ADR-0043), so a positionalp1 p2becomesmean: .. , sd: ... Concrete families override; the length must matchn_params(the record buildsp1/p2/p3from the first three).
- frozen = None¶
The underlying scipy frozen distribution, or
None.
- has_bounded_support = False¶
Whether the family’s support is finite – drives reflecting-bounds eligibility and latin-hypercube participation.
Uniformoverrides.
- has_prior = True¶
Whether the family has a proper distribution (
Falseonly forNoPrior).
- logpdf_jax(u)[source]¶
JAX-traceable log prior density at sampling-space
u(ADR-0059).The gradient-based reference sampler (
job_type = hmc) composes its target log-density entirely from these per-family JAX logpdfs plus the model’s JAX NLL, sojax.graddifferentiates it. Every family in the edition-2 catalog overrides this with a hand-written JAX density, oracle-checked against its scipylogpdf(ADR-0059 item 4), so this base implementation is the fallback for a family that has not supplied one – it raises a pointed error rather than silently producing a wrong target.uis a JAX scalar; the return is a JAX scalar.
- n_params = 2¶
How many config numbers the family’s parameterization takes –
2for the location/scale/bounds families; the one-parameter families (exponential/chisquare/ rayleigh, the half-* scale priors) override to1so the positional grammar admits a single number (ADR-0010/#417); the three-parameter families (student_t) override to3. An_params >= 3family is authored only through the new-eraparameter:record – the legacy positional*_vargrammar carries at most two numbers, sovar_keyword_grammaromits it (ADR-0057).
- abstractmethod rvs(rng)[source]¶
Draw one sample in sampling space
uusingrng.rngis the caller’snumpy.random.Generator; it is passed to scipy asrandom_stateso prior sampling draws from the algorithm’s seeded Generator rather than NumPy’s legacy global RNG.
- support_lo_u = -inf¶
The family’s natural lower support endpoint in sampling space
u(the lower edge ofsupport(), a family constant independent of the distribution’s parameters).-inffor the doubly-unbounded families; the positive-support families (gamma/exponential/chisquare/rayleigh, the half-* scale priors, inv_gamma/weibull, and beta’s[0,1]) override to0.0. The owningFreeParameter’sScale.inversemaps it to the theta-space floor a one-sided truncation measures bounds against (ADR-0047).
- class pybnf.priors.Scale[source]¶
Base class for a parameter scale (an abstract
theta <-> utransform).- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
- class pybnf.priors.TruncatedPrior(inner, lo_u, hi_u)[source]¶
An inner
Priorfamily confined to[lo_u, hi_u]inu.Density is the inner family’s, renormalized over the box (
logpdf = inner.logpdf - log Zinside,-infoutside). Sampling and the inverse CDF go through the truncated inverse-CDF, so a draw lands inside the box by construction (not an unbounded draw folded back).Zis parameter-independent, so it cancels in the MCMC acceptance ratio and in MAP optimization (ADR-0003); it is kept only so reported densities are genuinely those of the truncated distribution.- has_bounded_support = True¶
Whether the family’s support is finite – drives reflecting-bounds eligibility and latin-hypercube participation.
Uniformoverrides.
- has_prior = True¶
Whether the family has a proper distribution (
Falseonly forNoPrior).
- logpdf(u)[source]¶
Renormalized log density:
inner.logpdf(u) - log Zin the box, else-inf. The-log Zconstant cancels for inference but makes the reported value the true truncated-density log-pdf.
- logpdf_jax(u)[source]¶
JAX log-density of the truncated family (ADR-0059): the inner family’s
logpdf_jaxrenormalized by-log Zinside[lo_u, hi_u],-infoutside – the JAX peer oflogpdf(). The safe-udouble-whereevaluates the inner density at the box midpoint outside the box (a point guaranteed in-support, sinceZ > 0requires the box to carry inner mass), then masks, sojax.gradstays finite (0) outside the box (the same autodiff guard the positive-support families use).This is the density of the truncated prior; like
Uniform, thehmcsampler reparameterizes the boxu = lo_u + (hi_u-lo_u) sigmoid(z)(pybnf.priors.bijector), so NUTS samples an unboundedzand a truncation wall is unreachable – the retained mass is sampled divergence-free even when it leans against a bound (ADR-0059 item 5).
- ppf(q)[source]¶
Truncated inverse CDF over
[lo_u, hi_u]: mapq in [0, 1]onto the retained CDF interval, then invert with the inner family’sppf.
- pybnf.priors.bijector_for_support(lo, hi)[source]¶
The unconstraining bijector for a prior whose sampling-space support is
(lo, hi).Keys on the finiteness of each endpoint (the support shape), so one factory serves every family: an unbounded support is the identity, one finite endpoint is a log/exp half-line map, two finite endpoints are the logit/sigmoid box map.
- pybnf.priors.build_prior(keyword, p1, p2, p3=None)[source]¶
Resolve a
*_varkeyword + config values to aPriorand its scale.Returns
(prior, scale). The single entry point used byFreeParameterso the keyword->(family, scale) mapping lives in exactly one place (ADR-0010, M2.3).p3carries the third distribution parameter of a three-parameter family (student_t’sscale, afterdf/location); it isNonefor the one- and two-parameter families and the no-prior carriers (ADR-0057). The familybuildclassmethods all accept it (trailing-optional), so it is passed uniformly.An unrecognised keyword falls back to
(NoPrior, LINEAR)– a linear, unbounded, no-prior value carrier – preserving the legacy_make_distributionbehavior, which returnedNone(no usable distribution) for any type outside the four*_varfamilies. Real config keywords are validated upstream byparse.py’s grammar; a registry that failed to generate the known keywords would be caught by the keyword-map unit tests, not silently swallowed here.
- pybnf.priors.var_keyword_grammar()[source]¶
Partition the prior families’
*_varkeywords forparse.py’s grammar (ADR-0010). Returns(bounded_keywords, unbounded_keywords, one_param_keywords): each familybcontributes{b}_var(linear) andlog{b}_var(log10), routed byhas_bounded_support– bounded-support families take the optionalb/uflag, unbounded ones don’t.one_param_keywordsis the subset (ofunbounded_keywords) whose family takes a single config number (n_params == 1: exponential/chisquare/rayleigh, the half-* scale priors) – so the grammar requires exactly one number for them and two for the rest.A
n_params >= 3family (student_t, ADR-0057) is omitted entirely: the legacy positional<family>_var = id p1 p2grammar carries at most two numbers (and a three-token value already means a bounded box plus its reflecting-bounds flag), so a third parameter has no unambiguous positional home. Such a family is authored only through the new-eraparameter:record (ADR-0043), which names each field and reads them viaPrior.field_names– the family stays inPRIOR_KEYWORD_MAP(so the record path resolves it), it just gets no positional keyword.The no-prior
var/logvarkeywords are handled separately byparse.py.
The Prior abstraction¶
The Prior abstraction: a distribution family evaluated entirely in the
sampling space u (ADR-0010).
A Prior is scale-agnostic – it knows nothing about theta or
log10. The owning FreeParameter holds the Scale and applies the
theta <-> u transform, calling prior.logpdf(scale.forward(theta)) and
scale.inverse(prior.rvs(rng)). This keeps each family’s math pure and the
scale in one place (ADR-0003).
Concrete families (Normal, Uniform, …) live one-per-file and
self-register with @register_prior_family. NoPrior is the first-class
null-object for var/logvar Simplex start points: a free parameter with a
scale but no distribution.
- class pybnf.priors.base.FrozenPrior[source]¶
A
Priorbacked entirely by ascipy.statsfrozen distribution in the sampling spaceu(ADR-0010).Every location/scale/shape family (Normal, Laplace, Cauchy, Gamma, Exponential, ChiSquare, Rayleigh) has the same density/sampling/inverse-CDF/support shape – a thin delegation to its frozen distribution – so it lives here once. A subclass sets
self.frozenin__init__(andhas_bounded_supportas a class attribute) and provides the family-specificbuildclassmethod.NoPrior(no distribution) andUniform(a custom latin-hypercubeppf) do not use this base.
- class pybnf.priors.base.NoPrior[source]¶
The absence of a prior: a
var/logvarSimplex start point.Contributes nothing to the log prior, cannot be sampled, and has no support. It still pairs with a
Scale(logvarisLog10); the scale lives on theFreeParameter, not here.- classmethod build(p1, p2, scale, p3=None)[source]¶
Factory matching the family
buildsignature;p1/p2/p3/scaleare ignored – a no-prior parameter carries only a start value.
- field_names = ()¶
The config field names for the family’s distribution parameters, in
build()order – the new-eraparameter:record names each one (ADR-0043), so a positionalp1 p2becomesmean: .. , sd: ... Concrete families override; the length must matchn_params(the record buildsp1/p2/p3from the first three).
- frozen = None¶
The underlying scipy frozen distribution, or
None.
- has_bounded_support = False¶
Whether the family’s support is finite – drives reflecting-bounds eligibility and latin-hypercube participation.
Uniformoverrides.
- has_prior = False¶
Whether the family has a proper distribution (
Falseonly forNoPrior).
- logpdf_jax(u)[source]¶
A no-prior carrier contributes
0to the HMC target (ADR-0059), the JAX peer oflogpdf(). Returned as a JAX scalar so it sums cleanly with the family logpdfs without forcing a host/device transfer.
- class pybnf.priors.base.Prior[source]¶
A distribution family operating in the sampling space
u.Subclasses expose
logpdf/rvs/ppfinuand report theirsupport(inu) andhas_bounded_support.frozenis the underlyingscipy.statsfrozen distribution (orNoneforNoPrior), surfaced forFreeParameter._distributionback-compat.- field_names = ('p1', 'p2')¶
The config field names for the family’s distribution parameters, in
build()order – the new-eraparameter:record names each one (ADR-0043), so a positionalp1 p2becomesmean: .. , sd: ... Concrete families override; the length must matchn_params(the record buildsp1/p2/p3from the first three).
- frozen = None¶
The underlying scipy frozen distribution, or
None.
- has_bounded_support = False¶
Whether the family’s support is finite – drives reflecting-bounds eligibility and latin-hypercube participation.
Uniformoverrides.
- has_prior = True¶
Whether the family has a proper distribution (
Falseonly forNoPrior).
- logpdf_jax(u)[source]¶
JAX-traceable log prior density at sampling-space
u(ADR-0059).The gradient-based reference sampler (
job_type = hmc) composes its target log-density entirely from these per-family JAX logpdfs plus the model’s JAX NLL, sojax.graddifferentiates it. Every family in the edition-2 catalog overrides this with a hand-written JAX density, oracle-checked against its scipylogpdf(ADR-0059 item 4), so this base implementation is the fallback for a family that has not supplied one – it raises a pointed error rather than silently producing a wrong target.uis a JAX scalar; the return is a JAX scalar.
- n_params = 2¶
How many config numbers the family’s parameterization takes –
2for the location/scale/bounds families; the one-parameter families (exponential/chisquare/ rayleigh, the half-* scale priors) override to1so the positional grammar admits a single number (ADR-0010/#417); the three-parameter families (student_t) override to3. An_params >= 3family is authored only through the new-eraparameter:record – the legacy positional*_vargrammar carries at most two numbers, sovar_keyword_grammaromits it (ADR-0057).
- abstractmethod rvs(rng)[source]¶
Draw one sample in sampling space
uusingrng.rngis the caller’snumpy.random.Generator; it is passed to scipy asrandom_stateso prior sampling draws from the algorithm’s seeded Generator rather than NumPy’s legacy global RNG.
- support_lo_u = -inf¶
The family’s natural lower support endpoint in sampling space
u(the lower edge ofsupport(), a family constant independent of the distribution’s parameters).-inffor the doubly-unbounded families; the positive-support families (gamma/exponential/chisquare/rayleigh, the half-* scale priors, inv_gamma/weibull, and beta’s[0,1]) override to0.0. The owningFreeParameter’sScale.inversemaps it to the theta-space floor a one-sided truncation measures bounds against (ADR-0047).
Parameter scale¶
Parameter Scale – the space a free parameter is sampled, proposed, and stored in (ADR-0003, ADR-0010).
A Scale owns the theta <-> u transform between a parameter’s stored
value theta and the sampling space u the prior family and the proposal
arithmetic both operate in. Linear is the identity; Log10 is base-10
log (u = log10(theta)); Ln is natural log (u = ln(theta)). The
transform lives here, in one place, so the log/exp boundary is not smeared
across FreeParameter.add / _reflect / prior_logpdf / sample_value
(which all go through _scale) – so a new base composes for free there.
The scales are concrete singletons – LINEAR, LOG10, LN – not a
registry. Each carries an explicit name so its base is never ambiguous in
output (ADR-0022: every log scale names its base; there is no bare “log”); the
native parameter: record (ADR-0043) selects one by name
(parameter_scale: linear|log10|ln). Log10.inverse is 10.0 ** u to
match exp10 and the inline 10** of the proposal arithmetic, bit-for-bit;
Ln.inverse is np.exp(u).
- class pybnf.priors.scale.Linear[source]¶
-
- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
- class pybnf.priors.scale.Ln[source]¶
-
- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
- class pybnf.priors.scale.Log10[source]¶
-
- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
- class pybnf.priors.scale.Scale[source]¶
Base class for a parameter scale (an abstract
theta <-> utransform).- inverse_jax(u)[source]¶
JAX-traceable peer of
inverse()(theu -> thetamap, ADR-0059).The gradient-based
hmcsampler evaluates the model’s NLL attheta = scale.inverse(u)and needs that step inside the autodiff graph, so a log-scaled parameter composes with NUTS.10.0 ** ualready traces under JAX, butnp.exp/np.log10do not, so each scale supplies ajnppeer. No change-of-variables Jacobian is added for this transform – the prior is defined inu(ADR-0010), sothetaenters only through the likelihood. The default raises, mirroringinverse().
Bounded support¶
Two family-agnostic decorators confine an otherwise unbounded family to a finite
region: truncated renormalizes the density over a box for
the gradient-free samplers, and bijector supplies the
change-of-variables the HMC/NUTS reference sampler uses instead.
The TruncatedPrior decorator: a family confined to a finite box in the
sampling space u (ADR-0020, issue #411).
PEtab v2 truncates a prior by the parameter’s lowerBound/upperBound, so a
normal prior with finite bounds is a truncated normal. PyBNF’s
unbounded-support families (Normal, Laplace, and their log forms) could not carry
bounds; this wraps any such family in a decorator that renormalizes the density
over [lo_u, hi_u] and samples inside the box by inverse-CDF.
Truncation is a hybrid concern (ADR-0010): it changes both the family’s support
and its normalization. This decorator owns both halves of the distribution math
in one family-agnostic place, while the owning FreeParameter
owns the matching reflecting box (the bounds in theta). The decorator works
for any inner family backed by a scipy.stats frozen distribution – it reads
only cdf/ppf/logpdf – so no per-family code is needed (the M2.3
ethos).
The bounds lo_u/hi_u are in sampling space u: the owning
FreeParameter maps the theta box through its Scale before wrapping, so
a log-scale parameter truncates in log10 space (the same space its family and
proposal arithmetic already live in).
- class pybnf.priors.truncated.TruncatedPrior(inner, lo_u, hi_u)[source]¶
An inner
Priorfamily confined to[lo_u, hi_u]inu.Density is the inner family’s, renormalized over the box (
logpdf = inner.logpdf - log Zinside,-infoutside). Sampling and the inverse CDF go through the truncated inverse-CDF, so a draw lands inside the box by construction (not an unbounded draw folded back).Zis parameter-independent, so it cancels in the MCMC acceptance ratio and in MAP optimization (ADR-0003); it is kept only so reported densities are genuinely those of the truncated distribution.- has_bounded_support = True¶
Whether the family’s support is finite – drives reflecting-bounds eligibility and latin-hypercube participation.
Uniformoverrides.
- has_prior = True¶
Whether the family has a proper distribution (
Falseonly forNoPrior).
- logpdf(u)[source]¶
Renormalized log density:
inner.logpdf(u) - log Zin the box, else-inf. The-log Zconstant cancels for inference but makes the reported value the true truncated-density log-pdf.
- logpdf_jax(u)[source]¶
JAX log-density of the truncated family (ADR-0059): the inner family’s
logpdf_jaxrenormalized by-log Zinside[lo_u, hi_u],-infoutside – the JAX peer oflogpdf(). The safe-udouble-whereevaluates the inner density at the box midpoint outside the box (a point guaranteed in-support, sinceZ > 0requires the box to carry inner mass), then masks, sojax.gradstays finite (0) outside the box (the same autodiff guard the positive-support families use).This is the density of the truncated prior; like
Uniform, thehmcsampler reparameterizes the boxu = lo_u + (hi_u-lo_u) sigmoid(z)(pybnf.priors.bijector), so NUTS samples an unboundedzand a truncation wall is unreachable – the retained mass is sampled divergence-free even when it leans against a bound (ADR-0059 item 5).
- ppf(q)[source]¶
Truncated inverse CDF over
[lo_u, hi_u]: mapq in [0, 1]onto the retained CDF interval, then invert with the inner family’sppf.
Support-aware unconstraining bijections for gradient-based sampling (ADR-0059 item 5).
The gradient-free samplers (am / dream / p_dream) keep a draw inside a
constrained prior support with reflecting bounds – a Metropolis device with no HMC
analogue. NUTS, by contrast, samples an unbounded momentum-driven trajectory; at a
-inf support wall (a positive-support prior’s u <= 0, beta’s [0, 1], a
TruncatedPrior box) the leapfrog integrator diverges.
The fix is a change of variables: HMC samples an unconstrained z in R, mapped to the
prior’s support by a monotone bijection u = b(z), and the target gains the Jacobian term
log|b'(z)|. Because b lands strictly inside the open support for every finite z,
the -inf wall (and the divergence it caused) is never reached.
The transform is a property of the support shape, not the family, so it lives here once and
keys purely on support() (the (lo, hi) finiteness pattern) – the same family-agnostic
ethos as truncated. Four cases cover the whole catalog:
support |
|
|
|
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Each bijector exposes a numpy to_unconstrained / to_constrained / logdet (host-side
init seeding and draw-writing) and a JAX-traceable to_constrained_jax / logdet_jax (the
differentiable target the hmc sampler composes), mirroring Scale’s
inverse / inverse_jax split. jax is imported lazily so importing this module (and the
whole priors package) never requires the optional pybnf[jax] extra.
- class pybnf.priors.bijector.Bijector[source]¶
A monotone unconstraining map
u = b(z)fromRonto a prior’s support.to_constrainedisb(z -> u);to_unconstrainedisb^{-1}(u -> z, used once to seed NUTS from the latin-hypercube start point);logdetis the change-of-variables Jacobianlog|b'(z)|added to the HMC target. The*_jaxpeers are the JAX-traceable forms the differentiable log-density uses.- to_constrained_jax(z)[source]¶
JAX-traceable
to_constrained()(the differentiable target).
- class pybnf.priors.bijector.BoxBijector(lo, hi)[source]¶
Finite box support
(lo, hi):u = lo + (hi-lo)*sigmoid(z), withlog|b'(z)| = log(hi-lo) + logsigmoid(z) + logsigmoid(-z). Coversuniform/loguniformboxes,beta’s[0, 1], and a two-sidedTruncatedPrior.sigmoid(z) in (0, 1)for every finitez, soustays strictly inside the box – both walls are unreachable.- to_constrained_jax(z)[source]¶
JAX-traceable
to_constrained()(the differentiable target).
- class pybnf.priors.bijector.IdentityBijector[source]¶
Unbounded support
(-inf, inf):u = z, no Jacobian. The real-support families (normal/laplace/cauchy/student_t/gumbel/logistic, and anylognormal_varwhose prior is a normal inu) need no reparameterization, so HMC samples them inudirectly.- to_constrained_jax(z)[source]¶
JAX-traceable
to_constrained()(the differentiable target).
- class pybnf.priors.bijector.LowerBoundedBijector(lo)[source]¶
Half-line support
(lo, inf):u = lo + exp(z),log|b'(z)| = z. Covers the positive families (gamma/exponential/chisquare/rayleigh/weibull/inv_gamma/the half-* scale priors), whoselois0.exp(z) > 0for every finitez, sou > lostrictly – theu <= lowall is unreachable.- to_constrained_jax(z)[source]¶
JAX-traceable
to_constrained()(the differentiable target).
- class pybnf.priors.bijector.UpperBoundedBijector(hi)[source]¶
Half-line support
(-inf, hi):u = hi - exp(z),log|b'(z)| = z. The mirror ofLowerBoundedBijector(no catalog family is upper-only by default, but a one-sided upperTruncatedPriorlands here);u < histrictly.- to_constrained_jax(z)[source]¶
JAX-traceable
to_constrained()(the differentiable target).
- pybnf.priors.bijector.bijector_for_support(lo, hi)[source]¶
The unconstraining bijector for a prior whose sampling-space support is
(lo, hi).Keys on the finiteness of each endpoint (the support shape), so one factory serves every family: an unbounded support is the identity, one finite endpoint is a log/exp half-line map, two finite endpoints are the logit/sigmoid box map.