Skip to content

Plan

Deriving a program's target plan from its checked kernel module, and the lowering entry point every target renders from.

plan

The target plan of a program, derived from its checked kernel module.

A program is one named computation of the checked QiecModule, performing Random.sample and Score.add on the module's canonical instances, binding pure values, and calling its marginalization helpers. A probabilistic-programming target has statements for exactly those things: a draw, an observation, a deterministic binding, a log-density increment, and an integration scope. The plan pass reads the computation and recognizes each of them, producing the IRProgram body the renderers consume: one IRSample per Random.sample request, one IRObserve per scored density at an observation, one IRDeterministic per pure binding, one IRScore per other weight, and one IRMarginalize per helper call whose answer is scored. The plan's inputs are the entry point's parameters, typed by the module and constrained by how the body reads them.

The pass reads the source declarations only for what the module does not carry: object cardinalities and bounds, the morphism a site draws through (which fixes a class-index draw's alphabet and a structured family's wire form), and the option blocks of structured families. A construct the target vocabulary has no statement for, a call of a deduction or a recurrence, is reported with the kind of the request or call the plan cannot place, so a renderer never receives a body with a hole in it.

TARGET_NAME_SEPARATOR module-attribute

TARGET_NAME_SEPARATOR = '__'

How a target spells the $ of a name a program draw renamed.

theta$z is the site of the local z of a program drawn under theta, and no target language admits $ in an identifier.

Lower

Bases: Mapping[Module, IRProgram]

Map a parsed Module to an IRProgram.

The lowering elaborates the module through the QIEC route first; the program's plan is then derived from its checked computation. A module without a program lowers to its checked computations alone. Stateless: every table is derived from the input module on each call.

forward

forward(module: Module, *, target: str = 'ir', optimize: bool = True) -> IRProgram

Lower a parsed module to the transpile IR.

PARAMETER DESCRIPTION
module

The parsed module, with composite lets already expanded for the target.

TYPE: Module

target

The transpile target the lowering serves, named in the diagnostics the QIEC boundary raises.

TYPE: str DEFAULT: 'ir'

optimize

Whether to derive the target-oriented probabilistic plan. When false, retain only the checked QIEC graph so reference execution can test semantics before target-plan recognition or rewriting.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
IRProgram

The lowered program with its checked kernel module.

RAISES DESCRIPTION
UnsupportedConstruct

If the module has no program and no QIEC surface, uses a construct the elaboration does not admit, or falls in a gap of the elaboration.

QiecDiagnosticError

If a QIEC declaration is rejected.

Source code in src/quivers/transpile/plan.py
def forward(
    self, module: Module, *, target: str = "ir", optimize: bool = True
) -> IRProgram:
    """Lower a parsed module to the transpile IR.

    Parameters
    ----------
    module : Module
        The parsed module, with composite lets already expanded for
        the target.
    target : str
        The transpile target the lowering serves, named in the
        diagnostics the QIEC boundary raises.
    optimize : bool
        Whether to derive the target-oriented probabilistic plan. When
        false, retain only the checked QIEC graph so reference execution
        can test semantics before target-plan recognition or rewriting.

    Returns
    -------
    IRProgram
        The lowered program with its checked kernel module.

    Raises
    ------
    UnsupportedConstruct
        If the module has no program and no QIEC surface, uses a
        construct the elaboration does not admit, or falls in a
        gap of the elaboration.
    QiecDiagnosticError
        If a QIEC declaration is rejected.
    """
    qiec_module = checked_module(
        module,
        target=target,
        require_target_runtime=optimize,
    )
    if qiec_module is None:
        # A source with nothing to elaborate has no program either;
        # report the established precise ``program:absent`` error.
        pick_program(module)
        raise UnsupportedConstruct(f"qvr-{target}", ["program:absent"])
    if not any(
        isinstance(statement, ProgramDecl) for statement in module.statements
    ):
        qiec_ir = lower_qiec_ir(qiec_module)
        return IRProgram(
            name=qiec_ir.module, inputs=(), body=(), module=qiec_ir, cards={}
        )
    if qiec_module.gap:
        kind = qiec_module.gap.partition("; ")[0]
        raise UnsupportedConstruct(f"qvr-{target}", [kind])
    if not optimize:
        expanded = expand_composite_lets(module, target="stan")
        program = pick_program(expanded)
        return IRProgram(
            name=program.name,
            inputs=(),
            body=(),
            module=lower_qiec_ir(qiec_module),
            cards={},
        )
    plan = checked_program_plan(qiec_module, module, target)
    assert plan is not None
    return plan

checked_module

checked_module(module: Module, *, target: str, require_target_runtime: bool = True) -> QiecModule | None

Elaborate and check a module at the lowering boundary.

A source with nothing to elaborate takes no checking path. Otherwise the elaboration constructs the complete :class:~quivers.qiec.QiecModule and validate_module independently checks its nominal declarations, static scopes, effect rows, and every computation type. Capability analysis is deliberately separate: the lowering always retains the complete typed module, and a selected renderer uses :func:quivers.transpile.qiec_ir.analyze_qiec_capabilities to determine whether it can preserve each feature.

PARAMETER DESCRIPTION
module

The parsed module.

TYPE: Module

target

The transpile target, for diagnostics.

TYPE: str

require_target_runtime

Whether to reject host-only runtime capabilities before deriving a target plan. Disable this only when retaining the checked QIEC graph for reference execution without a target-oriented plan.

TYPE: bool DEFAULT: True

RETURNS DESCRIPTION
QiecModule | None

The checked module, or None when the source has nothing to elaborate.

RAISES DESCRIPTION
UnsupportedConstruct

If a program uses a form the elaboration does not admit; the construct is reported the way a renderer reports one it cannot emit.

QiecDiagnosticError

If a QIEC declaration is rejected.

Source code in src/quivers/transpile/plan.py
def checked_module(
    module: Module, *, target: str, require_target_runtime: bool = True
) -> QiecModule | None:
    """Elaborate and check a module at the lowering boundary.

    A source with nothing to elaborate takes no checking path. Otherwise
    the elaboration constructs the complete
    :class:`~quivers.qiec.QiecModule` and ``validate_module`` independently
    checks its nominal declarations, static scopes, effect rows, and every
    computation type. Capability analysis is deliberately separate: the
    lowering always retains the complete typed module, and a selected
    renderer uses
    :func:`quivers.transpile.qiec_ir.analyze_qiec_capabilities` to determine
    whether it can preserve each feature.

    Parameters
    ----------
    module : Module
        The parsed module.
    target : str
        The transpile target, for diagnostics.
    require_target_runtime : bool
        Whether to reject host-only runtime capabilities before deriving a
        target plan. Disable this only when retaining the checked QIEC graph
        for reference execution without a target-oriented plan.

    Returns
    -------
    QiecModule | None
        The checked module, or ``None`` when the source has nothing to
        elaborate.

    Raises
    ------
    UnsupportedConstruct
        If a program uses a form the elaboration does not admit; the
        construct is reported the way a renderer reports one it cannot
        emit.
    QiecDiagnosticError
        If a QIEC declaration is rejected.
    """
    if not has_qiec_surface(module):
        return None
    try:
        qiec_module: QiecModule = lower_qvr_to_qiec(module)
    except QiecDiagnosticError as error:
        if error.code == GAP_CODE:
            # A program using a chart or a network morphism has no
            # elaboration yet. The module's other declarations still
            # lower; the program itself reaches the renderer through its
            # plan alone, and the gap is recorded on the plan.
            qiec_module = lower_qvr_to_qiec(module, elaborate_programs=False)
            validate_module(qiec_module)
            return replace(qiec_module, gap=error.message)
        if error.code != "qiec-program" and error.program is None:
            raise
        raise UnsupportedConstruct(
            f"qvr-{target}", [_elaboration_kind(error.code, error.message)]
        ) from error
    validate_module(qiec_module)
    if require_target_runtime:
        _refuse_host_runtime_calls(qiec_module, target)
    return qiec_module

target_name

target_name(name: str) -> str

A source name as every target spells it.

PARAMETER DESCRIPTION
name

The name, as the reference machine labels it.

TYPE: str

RETURNS DESCRIPTION
str

The name with each $ a program draw introduced spelled as TARGET_NAME_SEPARATOR, two underscores.

Source code in src/quivers/transpile/plan.py
def target_name(name: str) -> str:
    """A source name as every target spells it.

    Parameters
    ----------
    name : str
        The name, as the reference machine labels it.

    Returns
    -------
    str
        The name with each ``$`` a program draw introduced spelled as
        ``TARGET_NAME_SEPARATOR``, two underscores.
    """
    return name.replace("$", TARGET_NAME_SEPARATOR)

program_plan

program_plan(module: QiecModule, source: Module, program: ProgramDecl, target: str) -> IRProgram

Derive a program's plan from its checked module.

PARAMETER DESCRIPTION
module

The checked module.

TYPE: QiecModule

source

The expanded source module.

TYPE: Module

program

The program.

TYPE: ProgramDecl

target

The transpile target.

TYPE: str

RETURNS DESCRIPTION
IRProgram

The plan.

Source code in src/quivers/transpile/plan.py
def program_plan(
    module: QiecModule, source: Module, program: ProgramDecl, target: str
) -> IRProgram:
    """Derive a program's plan from its checked module.

    Parameters
    ----------
    module : QiecModule
        The checked module.
    source : Module
        The expanded source module.
    program : ProgramDecl
        The program.
    target : str
        The transpile target.

    Returns
    -------
    IRProgram
        The plan.
    """
    return _Planner(module, source, target).plan(program)

checked_program_plan

checked_program_plan(module: QiecModule, source: Module, target: str) -> IRProgram | None

Derive a target plan from an existing checked module.

This is the target-planning half of Lower.forward for callers such as the CLI and language server that already hold the checked QIEC module. Reusing it avoids parsing and elaborating the source a second time.

PARAMETER DESCRIPTION
module

The checked module.

TYPE: QiecModule

source

The parsed source module.

TYPE: Module

target

The transpile target.

TYPE: str

RETURNS DESCRIPTION
IRProgram | None

The target plan, or None when the source declares no program.

RAISES DESCRIPTION
UnsupportedConstruct

If the program falls in an elaboration gap or its checked computation cannot be represented by the target plan.

Source code in src/quivers/transpile/plan.py
def checked_program_plan(
    module: QiecModule, source: Module, target: str
) -> IRProgram | None:
    """Derive a target plan from an existing checked module.

    This is the target-planning half of [`Lower.forward`][quivers.transpile.plan.Lower.forward]
    for callers such as the CLI and language server that already hold the checked
    QIEC module. Reusing it avoids parsing and elaborating the source a second time.

    Parameters
    ----------
    module : QiecModule
        The checked module.
    source : Module
        The parsed source module.
    target : str
        The transpile target.

    Returns
    -------
    IRProgram | None
        The target plan, or ``None`` when the source declares no program.

    Raises
    ------
    UnsupportedConstruct
        If the program falls in an elaboration gap or its checked computation
        cannot be represented by the target plan.
    """
    if not any(isinstance(statement, ProgramDecl) for statement in source.statements):
        return None
    expanded = expand_composite_lets(source, target="stan")
    program = pick_program(expanded)
    if module.gap:
        kind = module.gap.partition("; ")[0]
        raise UnsupportedConstruct(f"qvr-{target}", [kind])
    return program_plan(module, expanded, program, target)