bayesmith.graph.trace
Source-derived signatures and contracts. See the reference index for coverage and conventions.
Module contract
Tracing a model function into an explicit graph. The graph object is the ground truth; this module is sugar for producing one. Tracing runs the model **once**, so the structure it records must not depend on values -- which is exactly the static-DAG restriction the rest of the package relies on. Edges are declared by passing a :class:`NodeRef` returned by an earlier primitive, not by inspecting argument names. That keeps ``parents`` explicit and ordered, which is what ``fn`` and ``dist_fn`` are called with. A ``NodeRef`` (and likewise a ``PlateRef``) is bound to the recorder of the ``trace(...)`` call that created it, so a handle from a different trace is refused rather than silently resolving by name against whatever the active trace happens to have declared -- see ``_parent_names`` and ``_plate_names``. **Not thread-safe.** ``_STACK`` is a single process-global list. It supports nested ``trace(...)`` calls on one thread (an inner trace pushes and pops its own recorder around the outer one), but concurrent ``trace(...)`` calls from multiple threads race on the same stack and can attribute one thread's nodes to another thread's graph. Confine tracing to a single thread at a time.
NodeRef
Defined in bayesmith.graph.trace, line 35.
NodeRef(name: str, owner: _Recorder) -> NoneA handle to a declared node. Pass one to declare an edge. Bound to the recorder of the ``trace(...)`` call that created it. A parent must be a ``NodeRef`` minted by the *currently active* trace -- enforced in ``_parent_names`` -- so a handle leaked in from an outer or an earlier trace is refused instead of silently resolving against a same-named node the active trace happens to declare.
PlateRef
Defined in bayesmith.graph.trace, line 55.
PlateRef(name: str, owner: _Recorder) -> NoneA handle to a declared plate. Pass one as ``plate=`` to place a node. Owner-checked the same way as :class:`NodeRef`, for the same reason: without it, a plate name that merely *coincides* with one declared by a different (or an outer) trace would bind silently -- enforced in ``_plate_names``.
plate
Defined in bayesmith.graph.trace, line 160.
plate(name: str, size: int) -> PlateRefDeclare a repetition axis and return a handle to it.
const
Defined in bayesmith.graph.trace, line 170.
const(name: str, value: Any, *, plate: PlateRef | Iterable[PlateRef] | None=None) -> NodeRefDeclare a fixed input node.
det
Defined in bayesmith.graph.trace, line 185.
det(name: str, fn: Callable[..., Any], *parents: NodeRef, linear_in: Iterable[str]=(), plate: PlateRef | Iterable[PlateRef] | None=None) -> NodeRefDeclare a deterministic node; ``linear_in`` is optional legacy metadata. The compiler discovers supported affine structure from the computation, even when no parent is named in ``linear_in``.
sample
Defined in bayesmith.graph.trace, line 209.
sample(name: str, dist_fn: Callable[..., Any], *parents: NodeRef, support: Support | None=None, depends_on_prediction: bool=True, plate: PlateRef | Iterable[PlateRef] | None=None) -> NodeRefDeclare a latent probabilistic node. ``support`` and ``depends_on_prediction`` are dispatch-axis claims about the model, exactly like ``det``'s ``linear_in`` -- see :class:`~bayesmith.graph.nodes.Probabilistic` for what each default means and why. Nothing in P1 reads either.
observe
Defined in bayesmith.graph.trace, line 238.
observe(name: str, dist_fn: Callable[..., Any], *parents: NodeRef, obs: Any, mask: Any=None, support: Support | None=None, depends_on_prediction: bool=True, plate: PlateRef | Iterable[PlateRef] | None=None) -> NodeRefDeclare a probabilistic node conditioned on data. ``support`` and ``depends_on_prediction`` are dispatch-axis claims about the model, exactly like ``det``'s ``linear_in`` -- see :class:`~bayesmith.graph.nodes.Probabilistic` for what each default means and why. Nothing in P1 reads either. ``mask`` is boolean and shaped like ``obs``, ``True`` where the sample was actually taken; see :attr:`~bayesmith.graph.nodes.Probabilistic.observed_mask` for why an unobserved sample is declared here and not as an infinite scale.
joint_prior
Defined in bayesmith.graph.trace, line 275.
joint_prior(prior: Any) -> NoneDeclare a prior over SEVERAL latents at once -- one per graph.
A latent's own ``dist_fn`` is the prior on that one quantity. A Jeffreys
prior is a different shape of object: one density over a named block, read
off the forward model and the noise. Declaring it here rather than adding
``numpyro.factor`` by hand in a model is what makes the two scans of a
graph -- :func:`~bayesmith.graph.evaluate.log_joint` and
:func:`~bayesmith.bridge.numpyro_bridge.to_numpyro` -- read one
declaration instead of one of them silently missing it.
Order does not matter: it is a term of the joint, not a node, so it may be
declared before or after the latents it covers. The covered latents must
themselves be declared FLAT; the prior refuses a covered latent carrying a
proper density where it is evaluated, since that is two priors on one
quantity.
Raises:
GraphError: if a second one is declared. **Two Jeffreys blocks are not
two independent factors.** Each is the CONDITIONAL prior of its
block given the other latents, and a product of conditionals is in
general not the joint density of anything -- it is neither
declaration's prior, and nothing downstream reports the
difference. One block, named explicitly, is the declaration this
package can be held to. A model that genuinely wants both blocks
covered declares ONE prior over their union, which is a different
(and often non-existent) density -- see ``JeffreysPrior.over``.trace
Defined in bayesmith.graph.trace, line 319.
trace(model_fn: Callable[..., Any], *args: Any, **kwargs: Any) -> GraphRun ``model_fn`` once and return the graph it declared.