Source code for track_gen._src.gate_generator_registry
"""Gate-generator spec (canonical home of :class:`GateGeneratorSpec`) and the
deprecated module-level registry API.
``GateGenerator`` resolves ``config.generator`` once at construction through the public
registry, :data:`track_gen.plugin.registry` (kind ``"gate_generator"``). Built-in gate
generators register explicitly from ``track_gen._src.builtin_plugins``; third parties
use the ``"track_gen.plugins"`` entry point (see :mod:`track_gen.plugin`). Loading is
lazy, so importing ``track_gen`` stays cheap.
Backward-compatibility shims (kept working, deprecated quietly): ``register(spec)``
(the old rule: a name registered from another module raises, now as
``DuplicateSpecError`` (a ``ValueError``); a spec from the same module overwrites it, with
a ``DeprecationWarning``), ``get(name)``, ``available()``, ``_ensure_loaded()`` and
``GATE_GENERATORS`` (a read-only live view of the registry's gate-generator kind) all
delegate to :data:`track_gen.plugin.registry`.
"""
from __future__ import annotations
import dataclasses
import types
from typing import Callable, ClassVar
[docs]
@dataclasses.dataclass(frozen=True)
class GateGeneratorSpec:
"""One registered native gate generator (the legacy gate generator ABI).
Deprecated: write a Stage with ``kind="gate_generator"`` and
``output="anchors"`` (:ref:`writing-a-gate-generator`). A
``GateGeneratorSpec`` runs through an adapter stage until 1.0, and binding one
emits a ``DeprecationWarning``. Its ``max_gates`` callable is read only as the
adapter's capacity (the most gates ``generate`` writes, checked against
``GateGenConfig.min_gates`` / ``max_gates``).
capturable: whether ``generate`` obeys the CUDA-graph-capture contract (pure Warp,
no host sync, no per-call allocation). Defaults ``True``. A
``capturable=False`` generator may use host-side loop control and
per-call allocation; ``GateGenerator`` runs it EAGERLY on CUDA every
call (the same code path as ``cpu``), never building a ``wp.Graph``.
Mirrors ``GeneratorSpec.capturable``.
accepts_ctx: ``True`` when ``generate`` accepts a ``ctx=`` keyword (a
``track_gen.exec.LaunchContext``) and emits all of its device work
through it; the gate Program's legacy adapter stage
(``track_gen.stages.gates._LegacyGateSlot``) then calls
``generate(seeds_wp, config, out, scratch, ctx=ctx)``. Legacy plugins
leave it ``False`` and the adapter runs ``generate`` inside
``ctx.scope()``, so the ``warp_gate`` / ``warp_pipeline`` helpers they
call (which default ``ctx=None`` to the ambient context) inherit the
call's stream; their own direct ``wp.launch`` calls still go to Warp's
current stream. Mirrors ``GeneratorSpec.accepts_ctx``.
params: optional :class:`track_gen.plugin.Params` subclass (static fields only)
set through ``GateGenConfig.generator_params``; read as
``config.generator_params`` by ``generate`` / ``alloc_scratch`` /
``max_gates``. Mirrors ``GeneratorSpec.params``.
"""
#: Registry kind ``track_gen.plugin.registry.add(spec)`` infers for this spec type.
registry_kind: ClassVar[str] = "gate_generator"
name: str
alloc_scratch: Callable
generate: Callable
max_gates: Callable
supported_orderings: frozenset[str]
capturable: bool = True
accepts_ctx: bool = False
params: "type | None" = None
def _registry():
from ..plugin._registry import registry
return registry
def register(spec: GateGeneratorSpec) -> None:
"""Deprecated: use ``track_gen.plugin.registry.add(spec)``.
Keeps the old gate-registry rule: an existing name registered from another module
raises :class:`~track_gen.plugin.DuplicateSpecError` (a ``ValueError``, as before);
a spec from the same module overwrites it, with a ``DeprecationWarning``.
"""
_registry()._add_legacy(spec, "gate_generator", same_module_only=True)
def _ensure_loaded() -> None:
_registry()._ensure_loaded()
def available() -> list[str]:
"""Deprecated alias of ``track_gen.plugin.registry.available("gate_generator")``."""
return _registry().available("gate_generator")
def get(name: str) -> GateGeneratorSpec:
"""Deprecated alias of ``track_gen.plugin.registry.get("gate_generator", name)``."""
return _registry().get("gate_generator", name)
def __getattr__(name: str):
# GATE_GENERATORS: read-only live view of the registry's gate-generator kind.
if name == "GATE_GENERATORS":
reg = _registry()
reg._ensure_loaded()
return types.MappingProxyType(reg._table("gate_generator"))
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")