bayesmith.graph.reduction
Source-derived signatures and contracts. See the reference index for coverage and conventions.
Module contract
Atomically remove an integrated block and attach its evidence density. There is intentionally no public operation here that performs only one half. A caller either receives one :class:`ReducedGraph` whose underlying graph has reduced ``nodes`` and whose ``evidence_terms`` carry the replacement density, or receives no result at all. Keeping those facts in two fields of one returned value is the structural guard against evaluating the data twice. The wrapper is deliberately NUTS-only. Generic compilation starts by reading ``latents`` or ``nodes`` and is refused before an exact conditional sampler can silently omit the graph-level term.
ReducedGraph
Defined in bayesmith.graph.reduction, line 26.
class ReducedGraph(eqx.Module)
_graph: GraphAn atomically reduced graph that may only enter evidence-aware scans. ``log_joint`` and the NumPyro bridge unwrap this value explicitly. The ``nodes`` and ``evidence_terms`` remain inspectable as the two atomic products. The ``latents`` query that starts generic dispatch instead raises with the safe route, because those consumers do not read ``evidence_terms``. **The safe list is four, not three, and the fourth is not a new capability.** :func:`as_graph` has always been the documented route for "explicitly evidence-aware code"; what R5 found was that the refusal's own message named ``log_joint``, ``to_numpyro`` and ``nuts`` and not that, so a caller with exactly the consumer the escape hatch exists for was misdirected by it. Five of the R5 bake-off's twenty-one rows crashed here. ``compile_evidence_problem`` reads ``graph.latents`` on its first line and files every ``evidence_terms`` entry on the likelihood side, so it is the consumer this guard is protecting rather than one it should stop -- and the protection is real on its side, where a test asserts each term is filed exactly once. The guard is therefore left as it stands and the message is completed; ``ReducedGraph`` gains no fourth property, because a guard that special-cases one caller by name is a guard read by its spelling.
ReducedGraph.nodes
nodes(self) -> tuple[Any, ...]Retained nodes, in their original topological order.
ReducedGraph.latents
latents(self) -> tuple[str, ...]ReducedGraph.names
names(self) -> tuple[str, ...]Retained node names, in their original topological order.
ReducedGraph.evidence_terms
evidence_terms(self) -> tuple[Any, ...]The evidence declarations atomically attached by reduction.
ReducedGraph.as_graph
as_graph(self) -> GraphExpose the underlying graph to explicitly evidence-aware code.
as_graph
Defined in bayesmith.graph.reduction, line 90.
as_graph(graph: Graph | ReducedGraph) -> GraphUnwrap a reduced graph for an explicitly evidence-aware consumer.
check_evidence_nuts_boundary
Defined in bayesmith.graph.reduction, line 109.
check_evidence_nuts_boundary(graph: Graph, nuts_latents: Iterable[str]) -> NoneRefuse a graph-level likelihood that an exact block would omit.
reduce_with_evidence
Defined in bayesmith.graph.reduction, line 128.
reduce_with_evidence(graph: Graph, *, remove_latents: Iterable[str], absorb_observed: Iterable[str], evidence_term: Any, nuts_latents: Iterable[str]) -> ReducedGraphReturn the reduced graph with its replacement likelihood attached. ``remove_latents`` names the variables integrated out by ``evidence_term``. ``absorb_observed`` names the data whose likelihood is already inside that term. Deterministic descendants of either set are removed automatically; a probabilistic descendant must be named in the corresponding set, because silently pruning one would integrate a density the term did not declare. ``nuts_latents`` is an explicit witness supplied by the plan that will run the returned graph. The graph layer cannot import dispatch without reversing the package dependency, but it must still refuse a term over a non-NUTS block: the exact conditional samplers do not read graph-level density terms.