Lowering support¶
The support tables the plan derivation reads: object shapes and bounds,
family sentinels, argument constraints, and the wire forms they resolve
to. The module is implementation and exports no public names; the
lowering entry point is Lower.
lower
¶
The support tables of the plan.
A program's plan is derived from its checked kernel module by
quivers.transpile.plan; this module holds what
the derivation reads beside the module: the shapes, cardinalities, and
declared bounds of the source's objects, the family metadata's sentinel
instances and the argument constraints and supports read off them, the
wire forms an argument takes to satisfy a constraint, and the alphabet
of a class-index draw. Renderers consume the plan and do not materialize
PyTorch tensors.
The tables are implementation of the plan derivation and contribute no
public names; Lower is the entry point.
RealBounds
didactic-model
¶
Bases: Model
The {low=..., high=...} bounds a continuous object declares.
object Rate : Real 3 {low=0.0, high=1.0} names the box
[0, 1]^3 rather than R^3, so a variable whose event axis
or per-row value space is Rate lives in that box. Renderers
turn the pair into the target's own bounded declaration
(Stan's <lower=0, upper=1>, JAGS' T(0, 1), ...); a
variant with neither bound set is the unbounded default.
ObjectShape
didactic-model
¶
ObjectShape(*, extent: int | None = None, real_width: int | None = None, finite: bool = False, bounds: RealBounds = field(default_factory=RealBounds))
Bases: Model
The transpile-visible shape of one object declaration.
Three independent readings, one per position an object name can occupy (see the module docstring):
extentis the size the object contributes as an axis: the cardinality of a finite object (FinSet N, an enum set, a product of finite factors) and the total coordinate count of a continuous one (Real 28 28is 784 coordinates wide).real_widthis set only forReal, the one constructor whose value is a plain real vector, and is what a program-domain factor or a morphism codomain reads to size its wire.boundscarries the constructor's{low=..., high=...}.
finite separates the two readings of extent: a finite object
has |A| elements, so its extent is an alphabet a class index
can range over, while a continuous one has extent coordinates
and names no alphabet at all.
pick_program
¶
pick_program(module: Module) -> ProgramDecl
Pick the ProgramDecl the module's export designates.
When the module declares multiple programs, prefer one
referenced by an export declaration; otherwise pick the
last declared program.
An export naming a define binding rather than a program
is not a lowering target: a define is a morphism-level
composition (scan(cell) >> decoder), and the transpile
boundary is the probabilistic program. A define a step
references is unfolded by
expand_composite_lets
at the call site instead, so the recurrence a scan denotes
reaches the IR through the program that samples it.
Source code in src/quivers/transpile/lower.py
exported_return_names
¶
exported_return_names(module: Module) -> tuple[str, ...]
The variable names the module's exported program returns.
A QVR program declared prog : A -> B denotes a Markov kernel
from A to B, and its return clause names the components of
the value in B that the kernel carries. Those names are what a
faithful emit has to expose through the target's own return
surface, so they are the contract the export-equivalence tier
checks a backend against. An empty tuple means the program
declares no return clause and denotes only its joint.
Source code in src/quivers/transpile/lower.py
object_shapes
¶
object_shapes(module: Module) -> dict[str, ObjectShape]
Return name -> ObjectShape
for every object declaration in module, in source order.
Declarations are read in order so a later one can size itself
from an earlier name (object M : FinSet N5,
object Grid : Real Rows Cols) exactly as the runtime's
resolver does. A declaration whose value has no static size (a
FreeResiduated universe, a free monoid, a residuated slash)
contributes no entry, and every downstream caller treats an
absent name the way it always has.
Source code in src/quivers/transpile/lower.py
continuous_object_widths
¶
continuous_object_widths(module: Module) -> dict[str, int]
Return name -> width for every Real ... object declaration.
object State : Real 4 names a value in R^4: a program with
that object in its domain is applied to a 4-wide vector, and a
morphism with it as codomain writes one. object Img : Real 28
28 names a value in R^784, the runtime's own reading of a
multi-argument Real, so the width is the product of the
arguments rather than the first of them. object Step : FinSet
64 names an index axis instead, so it is absent here even
though
object_cardinalities
records its 64. The other continuous constructors (Simplex,
Sphere, Covariance, ...) carry a support a plain real
vector does not describe, so they are absent as well and a caller
that needs them has to read the constructor itself.
Source code in src/quivers/transpile/lower.py
object_bounds
¶
object_bounds(module: Module) -> dict[str, RealBounds]
Return name -> RealBounds
for every continuous object that declares {low=...} or
{high=...}. Objects with neither bound are absent.
Source code in src/quivers/transpile/lower.py
object_factors
¶
object_factors(expr: ObjectExpr) -> tuple[ObjectExpr, ...]
Flatten a product object expression into its factors, in source order. A non-product expression is its own single factor.
Source code in src/quivers/transpile/lower.py
object_cardinalities
¶
object_cardinalities(module: Module) -> dict[str, int]
Return name -> axis extent for every statically-sized object declaration.
The extent is what the object contributes in an axis position:
the cardinality of a finite object (FinSet N, an enum set, a
product of finite factors) and the coordinate count of a
continuous one (Real 28 28 is 784 wide). An object whose value
has no static size contributes no entry.
Source code in src/quivers/transpile/lower.py
axis_shape
¶
axis_shape(expr: ObjectExpr, cards: dict[str, int]) -> int | None
Return the cardinality of an axis object expression.
A product axis (A * B) is the flattened cardinality of its
factors, matching the runtime's ProductSet; a factor whose
size cards does not record makes the whole product unsized.
Source code in src/quivers/transpile/lower.py
build_shape_table
¶
build_shape_table(program: ProgramDecl, cards: dict[str, int]) -> dict[str, tuple[int, ...]]
Return name -> shape for every sample / observe / let binding
in program.
Source code in src/quivers/transpile/lower.py
exogenous_data_inputs
¶
exogenous_data_inputs(program: ProgramDecl, bound: set[str]) -> list[str]
Return the ordered list of exogenous identifier names
referenced in program but not bound by any step.
Sources: free names in let / score expressions; bracket-indexed
arg references (mu[cls] -> cls, mu); via= fibrations.
Order is deterministic by traversal order.
Source code in src/quivers/transpile/lower.py
free_vars_in_let
¶
free_vars_in_let(expr: LetExprNode) -> list[str]
Return the ordered list of free variable names in a let expression tree.
Source code in src/quivers/transpile/lower.py
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 | |
free_names_in_arg
¶
free_names_in_arg(arg: IRArg) -> list[str]
Return the ordered list of free names in an IR arg tree.
Source code in src/quivers/transpile/lower.py
arg_ref_shape
¶
arg_ref_shape(arg: IRArg, shape_table: dict[str, tuple[int, ...]]) -> tuple[int, ...]
Return the broadcast-evaluated shape of an IR arg referenced
through shape_table.
Source code in src/quivers/transpile/lower.py
lower_factors
¶
lower_factors(program: ProgramDecl, cards: dict[str, int]) -> dict[str, tuple[int, ...]]
Return name -> factor shape for every plated binding in
program. Mirror of build_shape_table
intended for renderers that need the factor shape (event_dims
plus batch_dims) of every name.
Source code in src/quivers/transpile/lower.py
inline_list_lets
¶
inline_list_lets(program: ProgramDecl) -> dict[str, tuple[str, ...]]
Return name -> tuple of element names for every let-step
whose RHS is a LetExprList
of bare-variable references.