bayesmithDocumentation0.10.0 source

bayesmith.dispatch.classify

Source-derived signatures and contracts. See the reference index for coverage and conventions.

Module contract
Which latents an exact method applies to, and how they group.

Affine groups are discovered from the primal computation with complementary
latents kept symbolic. ``linear_in`` remains compatible input metadata, but
neither its presence nor its absence decides membership. Structural proof,
finite numerical checks, Gaussian eligibility and covariance movement remain
separate evidence.

**Nothing here samples, and nothing here is jittable.** Every guard it calls
-- :func:`~bayesmith.exact.gaussian.check_gaussian`,
:func:`~bayesmith.exact.linearity.check_linearity`,
:func:`~bayesmith.exact.gls.check_prediction_dependence` -- runs on concrete
values and raises, so this whole module runs once, at compile time, outside
any trace.

**Exceptions are discriminated by raise SITE, not by type.**
:class:`~bayesmith.errors.NotGaussian` is a verdict about an ordinary model
and is caught wherever it appears. :class:`~bayesmith.errors.StructureError`
is caught at exactly one call site -- ``check_linearity``'s, where it means a
false ``linear_in`` and the block falls to NUTS naming its members -- and is
deliberately allowed through everywhere else, because from ``check_gaussian``
it means a node whose own ``log_prob`` contradicts the ``loc``/``scale`` read
off it, and routing that to NUTS would hide a broken model behind an
ordinary-looking fallback.

SIGMA_RTOL

Defined in bayesmith.dispatch.classify, line 63.

SIGMA_RTOL = 1e-08

Classification

Defined in bayesmith.dispatch.classify, line 81.

class Classification
exact: tuple[str, ...]
nuts: tuple[str, ...]
method: str
reason: str
linearity: dict[int, dict[float, float]] | None
sigma_movement: float | None
sigma_needs_rebuild: bool
structure: dict | None = None
discovery: Any = None
The partition of one graph, and the evidence behind it.

Attributes:
    exact: the single exact block, sorted. Empty if there is none.
    nuts: every other latent, sorted.
    method: ``"gcr"``, ``"gcr+snis"``, ``"gcr+mh"`` or ``"nuts"``.
    reason: why -- named members on a refusal, so a user one declaration
        away from an exact solve can see that from the plan.
    linearity: ``check_linearity``'s per-at-point errors, or ``None``.
    sigma_movement: the largest relative movement of sigma with the
        block, or ``None`` if there is no block. Measured from TWO
        anchors -- prior-scale probes around the prior centre, and the
        block's own Wiener solution, which is where the data put the
        posterior. See :func:`_sigma_movement` for why one of them is not
        enough.
    sigma_needs_rebuild: whether any observed node's scale has a latent
        ANCESTOR outside the block, in which case ``noise_std`` must be
        recomputed every sweep rather than hoisted. Distinct from
        ``sigma_movement``, which only sees movement with the BLOCK.

block_at

Defined in bayesmith.dispatch.classify, line 120.

block_at(graph: Graph, names: tuple[str, ...], *, env: dict[str, Any] | None=None) -> dict[str, Any]
``{outside latent: prior centre}`` -- where a block is built.

A block is affine *given* the latents outside it, so it has to be
anchored somewhere, and the prior's centre is the "before seeing
anything" point. Anchoring at zero instead is not equivalent and is not
merely a different starting guess: ``affine_only_at_zero``'s prediction is
affine exactly where its outside latent is zero, so a zero anchor accepts
at the caller's own at-point a model that the prior's centre refuses
there.

partition

Defined in bayesmith.dispatch.classify, line 526.

partition(graph: Graph, *, key: jax.Array | None=None) -> Classification
Derive the exact block and its method from the graph's structure.

Type a concept or API name.