Skip to content

Family Registry

Every distribution family is described once by a FamilySpec and registered in FAMILY_REGISTRY. The inline builders and conditional families dispatch on the registered specification, so registering a family through register_family (and refreshing the inline tables with reload_inline_registry) makes it available to programs.

family_spec

Single source of truth for every parametric distribution family the quivers stack supports.

A FamilySpec carries everything the three call paths need:

  • the conditional path (quivers.continuous.families._IndependentConditional) consumes params to know how to transform unbounded MLP outputs and how to instantiate a torch.distributions object;
  • the fixed inline path (quivers.continuous.inline.FixedDistribution) consumes params and support to construct a distribution from literal compile-time floats;
  • the mixed inline path (quivers.continuous.inline.MixedInlineDistribution) consumes the same spec to build a distribution whose parameters are stacked runtime tensors.

Every family registers itself exactly once via register; the inline and conditional generators read from the same record. This is the architectural seam that keeps the family catalog from duplicating itself across three modules.

FAMILY_REGISTRY module-attribute

FAMILY_REGISTRY: dict[str, FamilySpec] = {}

Every registered family specification, keyed by its DSL name.

ParamKind

ParamKind = Literal['scalar', 'vector', 'integer']

Per-parameter shape contract on the inline call side.

  • "scalar" — broadcasts across the codomain's last axis (one parameter value per per-codomain dimension, as in Normal(loc, scale)).
  • "vector" — a single vector parameter for the whole sample (used by Dirichlet whose concentration is the full simplex-dimensional vector, not a per-component scalar).
  • "integer" — a count-typed parameter (total_count for Binomial / NegativeBinomial / Multinomial); the fixed-factory accepts a Python int.

OutputKind

OutputKind = Literal['independent', 'vector', 'mvn', 'matrix', 'categorical', 'mixture']

How the distribution's output relates to the codomain.

The conditional path reads output_kind to decide whether to use the generic per-dim _IndependentConditional or a hand-written class. The inline path reads it to pick the matching codomain inference rule.

ParamSpec dataclass

ParamSpec(name: str, transform: str | Bijector, kind: ParamKind = 'scalar')

Spec for a single parameter of a distribution family.

A plain frozen dataclass rather than a dx.Model because transform accepts a Bijector instance, and the didactic model surface admits only registered scalar types in a union field. String-typed transforms retain a stable identity for panproto-side introspection via transform_name.

ATTRIBUTE DESCRIPTION
name

Keyword argument expected by the underlying torch Distribution constructor.

TYPE: str

transform

Either a string key registered in TRANSFORM_TO_BIJECTOR or a Bijector instance. The bijector's forward is applied to the raw parameter tensor on the conditional path; its full four-primitive interface is available to guides and pushforwards.

TYPE: str | Bijector

kind

Per-parameter shape contract on the inline call side.

TYPE: ParamKind

bijector property

bijector: Bijector

The resolved Bijector for this parameter.

For a string-typed transform, looks the key up in TRANSFORM_TO_BIJECTOR; for a Bijector-typed transform, returns it unchanged.

raw_transform property

raw_transform: Callable[[Tensor], Tensor]

The bijector's forward map, exposed as a plain callable.

For callers that treat the transform as Callable[[Tensor], Tensor].

inline_clamp property

inline_clamp: Callable[[Tensor], Tensor]

Inline safety-clamp callable for user-supplied literal or runtime parameters, sourced from resolve_inline_clamp.

transform_name property

transform_name: str

A stable string identifier for the transform.

Returns the registered key when transform is a string; returns a synthesised name based on the bijector class for Bijector-typed transforms.

FamilySpec dataclass

FamilySpec(name: str, dist_class: type, params: tuple[ParamSpec, ...], support: Constraint, discrete: bool = False, output_kind: OutputKind = 'independent', docstring: str = '', fixed_factory_override: Callable | None = None, mixed_builder_override: Callable | None = None, conditional_class_override: type | None = None)

Single source of truth for a distribution family.

Implemented as a plain @dataclass(frozen=True) rather than a didactic.api.Model because several fields are Python callables (fixed_factory_override, mixed_builder_override) or class objects (conditional_class_override) that don't translate to a panproto sort. ParamSpec is similarly a plain frozen dataclass since its transform field accepts a Bijector instance that has no didactic scalar registration.

Used by:

name instance-attribute

name: str

DSL key. Programs reference this name in <- F(args) lines.

dist_class instance-attribute

dist_class: type

The underlying torch.distributions class.

params instance-attribute

params: tuple[ParamSpec, ...]

Ordered parameter specs, matching the dist's positional / keyword API.

support instance-attribute

support: Constraint

Output support, used by variational guides to pick a bijector.

discrete class-attribute instance-attribute

discrete: bool = False

True for integer / categorical outputs.

output_kind class-attribute instance-attribute

output_kind: OutputKind = 'independent'

How the distribution's output relates to the codomain shape.

docstring class-attribute instance-attribute

docstring: str = ''

Used as the generated ConditionalX class docstring.

fixed_factory_override class-attribute instance-attribute

fixed_factory_override: Callable | None = field(default=None, repr=False)

Override for the all-literal FixedDistribution factory.

mixed_builder_override class-attribute instance-attribute

mixed_builder_override: Callable | None = field(default=None, repr=False)

Override for the mixed-mode dist builder (list[Tensor]) -> Distribution.

conditional_class_override class-attribute instance-attribute

conditional_class_override: type | None = field(default=None, repr=False)

Override for the conditional class (used by Categorical, Bernoulli, MultivariateNormal, etc.).

register_family

register_family(spec: FamilySpec) -> FamilySpec

Register a FamilySpec under its name; idempotent on re-registration of the same name to support hot-reload during development.

Source code in src/quivers/continuous/family_spec.py
def register_family(spec: FamilySpec) -> FamilySpec:
    """Register a `FamilySpec` under its name; idempotent on
    re-registration of the same name to support hot-reload during
    development.
    """
    FAMILY_REGISTRY[spec.name] = spec
    return spec

get_family_spec

get_family_spec(name: str) -> FamilySpec | None

Look up a registered family by DSL name; None if absent.

Source code in src/quivers/continuous/family_spec.py
def get_family_spec(name: str) -> FamilySpec | None:
    """Look up a registered family by DSL name; ``None`` if absent."""
    return FAMILY_REGISTRY.get(name)

family_names

family_names() -> tuple[str, ...]

Sorted tuple of every registered family name.

Source code in src/quivers/continuous/family_spec.py
def family_names() -> tuple[str, ...]:
    """Sorted tuple of every registered family name."""
    return tuple(sorted(FAMILY_REGISTRY))

build_torch_distribution

build_torch_distribution(spec: FamilySpec, params: list[Tensor] | dict[str, Tensor]) -> Distribution

Instantiate the underlying torch distribution from a list / dict of parameter tensors that have already been clamped to the family's constraints.

Source code in src/quivers/continuous/family_spec.py
def build_torch_distribution(
    spec: FamilySpec,
    params: list[torch.Tensor] | dict[str, torch.Tensor],
) -> D.Distribution:
    """Instantiate the underlying torch distribution from a list /
    dict of parameter tensors that have already been clamped to the
    family's constraints.
    """
    if isinstance(params, dict):
        kwargs = params
    else:
        kwargs = {p.name: t for p, t in zip(spec.params, params)}
    return spec.dist_class(**kwargs)

clamp_param

clamp_param(spec: FamilySpec, name: str, value: Tensor) -> Tensor

Apply the inline safety clamp for the named parameter of spec.

Source code in src/quivers/continuous/family_spec.py
def clamp_param(spec: FamilySpec, name: str, value: torch.Tensor) -> torch.Tensor:
    """Apply the inline safety clamp for the named parameter of
    ``spec``."""
    for p in spec.params:
        if p.name == name:
            return p.inline_clamp(value)
    raise KeyError(f"family {spec.name!r} has no parameter named {name!r}")