Encoders¶
Encoder is a torch.nn.Module that realizes an F-algebra
homomorphism T_Σ → Vec_D from terms over a signature to
fixed-length vectors. The framework supplies the recursion. The
analyst may specify the parametric function for each operation or use
the compiler-generated two-layer MLPs, whose input dimensions follow
the operation arguments.
For binders, the framework threads a typed de Bruijn context Γ through
the recursion. It compresses each binder's annotations in the outer
context, creates variable embeddings with var_init_fns, and recurses
over the scoped arguments in the extended context.
forward_graph compresses graph signatures. It applies an initial
embedder for each vertex kind, a finite number of message-passing
rounds with functions indexed by edge and vertex kind, and a readout
that reduces the final vertex embeddings to one graph-level vector.
encoder
¶
Encoder runtime: F-algebra homomorphisms T_Σ -> Vec_D.
A Encoder is a torch.nn.Module that, given a closed
Term over a signature, returns its vector embedding. The
recursion structure is supplied by the framework (algebra
homomorphism); per-operation parametric functions are supplied by
the user (declared in a encoder { … } DSL block) or by the
default scaffolding.
Canonical term form
A term over Σ has exactly one of three argument shapes at each position, determined by the codomain sort's kind:
- object: the argument is a
Termwhoseopis a constructor of Σ, a binder of Σ, or the reserved built-in"BoundVar". - data: the argument is a raw Python value (string, int, float, …) consumed by the encoder's per-data-sort embedder.
- index: the argument is a non-negative integer denoting a de-Bruijn index into the current scope context Γ.
No Term("Data", …) or other wrappings are accepted at runtime;
the canonical form is the only form.
The reserved "BoundVar" op is the built-in de-Bruijn reference:
Term("BoundVar", (i,)) at an object position reads the i-th
in-scope variable's embedding from Γ.
Binders thread a Context of in-scope variables: each entry
records the variable's sort, its embedding, and the type term
captured at binding. Compressing a binder constructor:
- Compresses each of the binder's
bindsarguments in the OUTER context. - Synthesises a fresh variable embedding from each via the
encoder's
var_initfunction. - Pushes the new entries onto Γ and recurses on the
scopedarguments under the extended context.
Graph-shaped signatures are compressed by forward_graph:
per-vertex-kind init seeds initial embeddings, finitely many
message_passing rounds alternate per-edge-kind message and
per-vertex-kind update functions, and a readout reduces
the final per-vertex embeddings to one fixed-length vector.
PerOpFn
dataclass
¶
PerOpFn(op: str, mode: PerOpMode, args: tuple[str, ...], fn: Callable[..., Tensor], state_var: str | None = None, prefix_var: str | None = None)
A per-operation parametric function.
mode is "plain" (algebra-hom), "recurrent"
(left-fold across a list-shaped signature) or "attention"
(each step sees a running prefix list). For plain rules,
fn is called with one positional argument per child
embedding; for recurrent / attention the framework
threads state / prefix arguments alongside the children.
Held as a plain dataclass (not a didactic Model) because the
fn field is a Python callable that doesn't round-trip
through panproto's schema translation.
| PARAMETER | DESCRIPTION |
|---|---|
op
|
The constructor or binder name the function interprets.
TYPE:
|
mode
|
How the function combines its children.
TYPE:
|
args
|
The names of the operation's arguments, in positional order.
TYPE:
|
fn
|
The function mapping child embeddings to the operation's embedding.
TYPE:
|
state_var
|
The name of the threaded state argument in
TYPE:
|
prefix_var
|
The name of the running-prefix argument in
TYPE:
|
Encoder
¶
Encoder(name: str, signature: Signature, sort_dims: dict[str, int], op_fns: dict[str, PerOpFn], var_init_fns: dict[tuple[str, str] | str, Callable[[Tensor | None], Tensor]], data_embedders: dict[str, Callable[[DataLeaf], Tensor]], modules_owned: list[Module] | None = None, iterations: int = 0, init_fns: dict[str, Callable[[DataLeaf], Tensor]] | None = None, message_fns: dict[str, Callable[..., Tensor]] | None = None, update_fns: dict[str, Callable[..., Tensor]] | None = None, readout: Callable[[list[Tensor]], Tensor] | None = None)
Bases: Module
An F-algebra homomorphism T_Σ -> Vec_D realised as an
nn.Module.
The graph-specific parameters (iterations, init_fns,
message_fns, update_fns, readout) are used only by
forward_graph on a graph-shaped signature.
| PARAMETER | DESCRIPTION |
|---|---|
name
|
Identifier used in diagnostics.
TYPE:
|
signature
|
The Σ whose terms this encoder consumes.
TYPE:
|
sort_dims
|
Per-sort embedding dimension.
TYPE:
|
op_fns
|
One entry per constructor and binder of Σ. The DSL compiler scaffolds defaults for omitted ops.
TYPE:
|
var_init_fns
|
Variable initialisers called at every binder to mint a fresh
embedding for each introduced variable. An annotated variable
is keyed by
TYPE:
|
data_embedders
|
One entry per data sort: |
modules_owned
|
Modules holding the parameters of the per-op functions, registered as submodules so their parameters train.
TYPE:
|
iterations
|
Number of message-passing rounds in
TYPE:
|
init_fns
|
Per-vertex-kind initial embedders.
TYPE:
|
message_fns
|
Per-edge-kind
TYPE:
|
update_fns
|
Per-vertex-kind
TYPE:
|
readout
|
TYPE:
|
Source code in src/quivers/structural/encoder.py
forward
¶
Encode a term to its embedding by structural recursion.
| PARAMETER | DESCRIPTION |
|---|---|
term
|
The term to encode.
TYPE:
|
ctx
|
The scope the term's free bound variables refer to;
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Tensor
|
The embedding of |
| RAISES | DESCRIPTION |
|---|---|
TypeError
|
If |
RuntimeError
|
If the term uses an operation, sort, or bound-variable index the encoder cannot interpret. |
Source code in src/quivers/structural/encoder.py
forward_graph
¶
Encode a graph by message passing followed by a readout.
Each vertex is initialised by its kind's initial embedder;
each of iterations rounds sends a message along every edge
(both ways for an undirected edge kind), averages each
vertex's inbox, and applies its kind's update function.
| PARAMETER | DESCRIPTION |
|---|---|
vertices
|
Each vertex's kind and payload.
TYPE:
|
edges
|
Each edge's kind, source index, and target index.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
Tensor
|
The readout of the final vertex embeddings. |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
If the signature is not graph-shaped, |
Source code in src/quivers/structural/encoder.py
582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 | |
make_default_op_fn
¶
make_default_op_fn(op: str, arg_dims: tuple[int, ...], out_dim: int) -> tuple[Module, Callable[..., Tensor]]
Build a parametric per-op function as a 2-layer MLP over concatenated child embeddings.
arg_dims is the tuple of per-argument dimensions in the
order in which the children are passed to the function. For
binders this is (annot_dim_1, …, annot_dim_k, scoped_dim_1,
…, scoped_dim_m). A nullary operation gets a learned constant
vector instead of an MLP.
| PARAMETER | DESCRIPTION |
|---|---|
op
|
The operation name, used in parameter names and diagnostics.
TYPE:
|
arg_dims
|
The embedding dimension of each child, in call order.
TYPE:
|
out_dim
|
The dimension of the operation's output embedding.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
tuple[Module, Callable[..., Tensor]]
|
The module owning the parameters, and the function that maps the child embeddings to the output embedding. |
| RAISES | DESCRIPTION |
|---|---|
RuntimeError
|
Raised by the returned function when it is called with a
number of children other than |
Source code in src/quivers/structural/encoder.py
make_default_var_init
¶
A parametric var_init(ty) function: an MLP mapping a type
embedding to a fresh variable embedding.
| PARAMETER | DESCRIPTION |
|---|---|
in_dim
|
The dimension of the type-annotation embedding.
TYPE:
|
out_dim
|
The dimension of the variable embedding.
TYPE:
|
| RETURNS | DESCRIPTION |
|---|---|
tuple[Module, Callable[[Tensor], Tensor]]
|
The MLP owning the parameters, and the function that maps a type embedding to a variable embedding. |
Source code in src/quivers/structural/encoder.py
Type aliases and constants¶
Structural compression: signatures, encoders, decoders, losses.
Runtime substrate for QVR signatures, encoders, decoders, and attached losses: a uniform algebraic interface for compressing structured objects to fixed-length vectors and decoding them under a learned distribution.
BOUND_VAR_OP
module-attribute
¶
The reserved op name of a bound-variable term.
A Term whose op is this name refers to a variable a binder
introduced. The signature compiler forbids it as a user-declared
constructor or binder name.
PerOpMode
¶
How a PerOpFn combines its children: "plain" applies the
function once, "recurrent" left-folds it across a list-shaped
signature, and "attention" gives each step the running prefix.