Semantics #
Denotational semantics for NN.IR.Graph.
This file defines an evaluator for the current IR fragment:
- it evaluates nodes in SSA/topological order,
- each node applies the corresponding spec-layer tensor operation to its parents,
- parameter payloads for
const,linear, andconvare supplied by an explicitPayload.
Partiality #
The evaluator returns Except String. It fails on malformed graphs (Graph.checkWellFormed),
on nodes whose parents or declared outShape violate the shape rules, on missing or mismatched
payloads (const flat length, linear dimensions, conv geometry, batchNormEval channels,
layernorm normalized suffix), and on malformed hard-mask shapes or flat lengths. .log rejects
an input tensor containing an entry <= 0 (or NaN),
because the spec logarithm is undefined there. A custom computation can also reject a missing
operand, an out-of-bounds read, or an output count beyond its index range. A pointwise operator
fails where its meaning at the scalar type rejects an entry, such as a zero divisor over the reals,
and where the scalar type has no meaning for it, such as erf in binary arithmetic. The remaining
operations are total on well-shaped inputs; reduceMean and layernorm divide by extents that
the shape rules already require to be positive, and mseLoss divides by the totalized
TorchLean.Tensor.meanDenominator rather than by the raw element count.
denoteAll runs the structural check but not Graph.checkShapes; each node instead checks its
parents' shapes locally and normalizeNodeOutput compares the computed shape with the declared
one. NN.IR.ShapeSoundness proves that on a graph accepted by checkShapes this final comparison
never fails. This equates evaluation with and without the final normalization on accepted
graphs; it does not prove that shape checking alone guarantees successful evaluation.
Softmax and layer norm:
softmax axisnormalizes independently along the zero-based tensor dimension named byaxis. The canonical specification handles every in-bounds dimension and preserves the tensor shape. This matches the meaning oftorch.softmax(x, dim=axis)in PyTorch.layernorm axismatches PyTorch'sF.layer_norm(x, normalized_shape=x.shape[axis:])convention:axisselects the start of the normalized suffix. We implement this by reshaping the tensor into a 2D view(seqLen, embedDim), applying the spec 2D LayerNorm (Spec.layerNorm), then reshaping back.
How this relates to PyTorch:
Graph.nodesis analogous to a topologically-sorted IR like FX/TorchScript.Payloadis analogous to “parameters / buffers / constants” that live outside the pure graph structure.- The evaluator is a pure, denotational model of running the graph. It is designed for clarity and for connecting to proofs and verification passes (not for performance).
References / related systems:
- PyTorch FX: https://pytorch.org/docs/stable/fx.html
- TorchScript: https://pytorch.org/docs/stable/jit.html
- ONNX (graph + initializers): https://onnx.ai/
Except helpers #
Permutation lowering #
Compute a sequence of adjacent swaps that realizes a valid rank-r target permutation.
This is used to implement .permute by repeatedly applying swapAdjacentAtDepth, which is already
available in the spec tensor library. Callers must validate the permutation first, as
permuteSomeTensor does with Shape.permute?. The errors below catch missing or out-of-range
entries encountered during lowering; duplicate axes and extra entries are not rejected.
Instances For
Permute a shape-tagged tensor according to perm.
This checks that perm is a valid permutation for the input shape (using Shape.permute?), then
lowers it to a sequence of adjacent swaps and applies them to the tensor.
Instances For
Evaluation helpers #
The evaluator itself (evalAt / denoteAll) is a fold over nodes. These helpers keep the fold
readable:
expectShapechecks a value's stored shape against the node's declaredoutShape.evalConst,evalLinear, andevalConvfetch and apply external payloads keyed by node id.
Check that a shape-erased tensor has the expected shape and recover its statically typed tensor.
Instances For
Evaluate MSE loss on two shape-erased tensors after checking that their stored shapes agree.
Instances For
MSE on shape-erased tensors of equal shape agrees with the shaped formula.
Transport a Tensor α (dim n scalar) across an equality n = n' (helper for payload casts).
Instances For
Apply one affine map independently at every index of an arbitrary leading shape.
Instances For
Multiply matrices independently at every index of a shared leading shape.
Instances For
Row-major matrix contraction using the shared broadcast and vector-promotion layout.
Instances For
matmulFlat with the batch offsets computed once per output entry and the contraction run by
Nat.fold. The products are added in the same order, so the results are bit-identical.
Instances For
Compiled code runs matmulFlatFast in place of matmulFlat.
Evaluate a checked matmul layout, retaining the typed matrix kernel for equal batch shapes.
Instances For
Evaluate a scaled contraction while retaining the original operands for coefficient replay.
Instances For
Evaluate a const node from the external payload.
Constants are stored “flat” (1D) for convenience, so we check the flattened length matches
Spec.Shape.size s and then unflatten to the requested shape.
Instances For
Evaluate a linear node from the external payload.
The final input axis must match inDim; every leading axis is preserved while the same affine map
$y=Wx+b$ is applied independently.
Instances For
Evaluate arbitrary-rank max pooling over the spatial suffix of a shape-erased tensor.
Instances For
Evaluate arbitrary-rank average pooling over the spatial suffix of a shape-erased tensor.
Instances For
Evaluate an arbitrary-rank convolution independently over every leading index.
Instances For
Evaluate fixed-statistics BatchNorm along an arbitrary channel axis.
Instances For
Normalize every present row; an empty batch has no coordinates to change.
Instances For
Layer normalization with a nonempty normalized dimension and explicit affine parameters.
Instances For
Layer normalization with unit scale, zero bias, and default epsilon.
Instances For
Affine data for a LayerNorm matrix view after validating its normalized suffix.
- gamma : TorchLean.Tensor α [embedDim]
- beta : TorchLean.Tensor α [embedDim]
- epsilon : α
Instances For
Resolve optional LayerNorm payload data into the vector shape consumed by the matrix semantics.
An absent payload means the standard unit scale, zero bias, and default normalization epsilon. Learned parameters are accepted only when their declared suffix is exactly the suffix normalized by the IR node.
Instances For
Decode a dynamic concat parent as a tensor with an existential leading dimension and the requested
tail shape. permuted selects the diagnostic for parents moved from another axis; it does not
change the shape check or tensor transport.
Instances For
Fold leading-axis concat over dynamic values that already share the same tail shape.
The permuted flag is passed only to the decoder's diagnostic.
Instances For
Evaluate a concat node from already evaluated parent values.
The IR concat operation accepts any valid axis. Tensor.concatAxisSpec takes any leading prefix,
but this evaluator only uses its axis-0 form (leading := .scalar). For another axis it moves
that axis to the front, folds Tensor.concatAxisSpec .scalar over the permuted parents, and moves
the result back. The IR execution and CROWN concat proofs are stated against this form.
Instances For
Normalize a node result to the node's declared shape, rejecting inconsistent implementations.
Instances For
A result whose shape matches the node declaration passes normalization unchanged.
A tensor at a literal node's declared shape passes normalization unchanged.
Read an already-evaluated parent, reporting the node and available prefix on failure.
Instances For
Evaluate tensor layout operations without requiring scalar arithmetic.
The same implementation serves homogeneous graphs and typed interpreters, including tensors of Boolean, integer, symbolic, or user-defined elements. Numerical operators are rejected here.
Instances For
Evaluate a pointwise operator from its meaning at the scalar type.
Every parent is read at the node's declared shape, and the meaning is applied to corresponding entries in row-major order. A missing meaning, a wrong parent count, or a meaning that rejects an entry is an error; the first rejected entry stops evaluation.
Instances For
Evaluate a known node from its already computed parent values, without the final declared-shape normalization.
This is the operator dispatch of the evaluator: each OpKind branch validates its parents,
applies the spec-layer operation, and returns a shape-erased value whose shape is computed by the
shared shape rules (NN.IR.OpContracts). evalNode wraps it with normalizeNodeOutput.
NN.IR.ShapeSoundness proves that the raw value already has the shape inferred by
Infer.nodeOutShape. The definition is a simp lemma so proofs about evalNode reduce the
selected branch exactly as before the split.
Instances For
Evaluate a known node from its already computed parent values.
Keeping operator dispatch (evalNodeRaw) separate from graph lookup lets local correctness proofs
reduce only the selected OpKind branch. The caller remains responsible for the graph's
topological invariant. The result is normalized to the node's declared outShape; on graphs
accepted by Graph.checkShapes that normalization is provably the identity.
Instances For
Evaluate node i after checking the graph's id discipline and retrieving the corresponding node.
denoteAll checks the full graph structure before repeatedly calling this one-step evaluator.
Instances For
Evaluate nodes i, i+1, ... given already computed prefix values vals.
Recursion decreases the number of unevaluated nodes.
Instances For
Evaluate a graph to a table of node values.
This returns an array vals of length g.size where vals[i] is the value of node i.
We do a structural well-formedness check once up front (ids/arity/topology). For lowering-produced
graphs, the boolean Graph.wellFormed check is a fast path; if it fails we fall back to the
exception-producing Graph.checkWellFormed so callers get a readable error message.
The evaluator always returns either:
.ok vals(all nodes evaluated successfully), or.error msgdescribing the first failure (malformed IR, missing payload, a local shape error, or a.logof a nonpositive entry, or a failed custom-computation read).
Graph.checkShapes is not run here: the per-node checks reject the same ill-shaped graphs, and the
existing lowering-correctness proofs unfold denoteAll with only the structural check in place.
NN.IR.ShapeSoundness.denoteAllRaw_eq_denoteAll shows that on a checkShapes-accepted graph the
per-node declared-shape normalization is redundant.
Instances For
Scoped notation #
Scoped notation for evaluating a graph to all node values.
Use with:
open scoped IR
g⟦payload, input⟧
Instances For
ASCII alternative to g⟦payload, input⟧.
Instances For
Evaluate the graph and return the value at outputId.