Operation Contracts #
Shared operation contracts for NN.IR.Graph.
Several IR passes need to agree on the same small set of “shape contracts”:
NN.IR.Infer: recompute output shapes from op parameters + parent shapes.NN.IR.Check: expose the documentedGraph.checkShapeswrapper.NN.IR.Semantics: evaluate nodes and reject ill-shaped graphs with readable error messages.
The point of this file is to keep shape arithmetic out of individual passes. If an op has nontrivial shape behavior (concat, matmul, pooling, convolution, LayerNorm flattening, axis moves), define the contract here first and call it from inference/semantics instead of copying the formula.
Small shape utilities #
These helpers are used by multiple IR passes, especially Infer and Semantics.
The output shape of flattening a tensor of shape s to a 1D vector.
Shape inference and the reference semantics both use this definition. It is a simp lemma so
that proofs about either pass see the concrete one-axis shape.
Instances For
Generic contract helpers #
These functions live outside any particular pass (Infer/Check/Semantics) so they can be
reused without introducing import cycles.
Check that an axis is in-bounds for a given shape.
Instances For
Validate the axis of an axis-dropping reduction (reduceSum, reduceMean).
The typed reductions Tensor.reduceSum and Tensor.reduceMean require the reduced axis to have
positive extent, so the shared IR rule is Spec.Shape.nonemptyAxis? rather than a bare rank
check: an in-bounds axis of extent zero is rejected by both inference and evaluation. The result
carries the evidence needed by the typed operation.
This is a simp definition so proofs that already know the nonemptyAxis? verdict can reduce it.
Instances For
Infer the shape obtained by swapping two arbitrary axes.
Instances For
Compute the matrix dimensions used to interpret layernorm axis.
TorchLean’s IR stores LayerNorm as an axis : Nat instead of a full normalized_shape tuple.
We interpret this in the same way the PyTorch exporter does:
normalized_shape = dims.drop axis
That is, we normalize over the suffix of dimensions starting at axis. To reuse the current
spec primitive (Spec.layerNorm), we flatten the input shape s into a matrix:
- the row count is the product of dimensions before
axis(dims.take axis); - the column count is the product of dimensions from
axisonward (dims.drop axis).
LayerNorm then runs over each row and the result is reshaped to s. This construction works for
every nonempty tensor rank; the matrix is an evaluation view, not a restriction on the input shape.
Instances For
Permutation (0-based axes) that moves axis to the last position, preserving the relative
order of the other axes.
Example: rank four with axis set to 1 yields [0,2,3,1].
Instances For
Permutation (0-based axes) that moves axis to the first position, preserving the relative
order of the other axes.
Example: rank four with axis set to 2 yields [2,0,1,3].
Instances For
Decomposition of a pair of matmul operand shapes into a shared leading shape and the three
matrix extents.
The left operand has shape leading ++ [rows, inner] and the right operand has shape
leading ++ [inner, cols]. Shape inference reads the output shape from this record and the
reference semantics uses the same record to recover the typed operands, so there is one matmul
shape rule.
- leading : Spec.Shape
Batch axes shared by both operands.
- rows : ℕ
Row count of the left operand.
- inner : ℕ
Contracted extent shared by both operands.
- cols : ℕ
Column count of the right operand.
Instances For
Shape of the left matmul operand.
Instances For
Shape of the right matmul operand.
Instances For
Shape of the matmul result.
Instances For
Decompose two matmul operand shapes.
Both inputs must have rank at least two and exactly the same leading shape. The final two axes
follow the usual matrix rule: (...×m×n) · (...×n×p) → (...×m×p).
This is a simp definition so that proofs about concrete operand shapes reduce the match.
Instances For
Infer the output shape for matmul from the two parent shapes (see matmulDims).
Instances For
A successful decomposition determines the operand shapes it was computed from.
Infer the output shape for concat from an array of parent shapes.
Every parent must have the same rank, the selected axis must exist, and all dimensions other than that axis must agree. The selected dimensions are summed. Both the axis and the tensor rank are arbitrary.
Instances For
Sliding-window shape arithmetic #
Convolution and pooling preserve a leading channel axis, but their admissible padding domains are not identical. The contracts below share validation and traversal while retaining the correct output formula for each operation family.
Effective kernel width for a dilated window.
Instances For
Output length for a dilated window with independent low/high padding.
Instances For
Infer pooling output lengths while enforcing the same basic window checks as graph validation.
Pooling uses poolOutDim, which assigns an empty output to an empty input axis, an oversized
window, or padding outside the pooling domain. Kernels and strides must still be positive.
Instances For
Validated shape information for pooling over a tensor suffix.
The plan is the common boundary between shape inference, denotational evaluation, and executable lowering. It carries the exact split and positivity evidence required by the typed pooling operators, so those passes cannot silently disagree about which axes are spatial.
- leading : Spec.Shape
Axes preserved before the pooled suffix.
- spatial : TorchLean.Tensor ℕ [config.spatialRank]
Input extents along the pooled axes.
The prefix and spatial suffix reconstruct the parent shape.
Every kernel extent is nonzero.
Every stride is nonzero.
Instances For
Output shape computed by a validated pooling plan.
Instances For
Validate and plan pooling over a spatial suffix of arbitrary rank.
Every preceding axis is preserved, so one operation handles unbatched tensors, ordinary batches, and tensors with several leading batch dimensions.
Instances For
Infer the output shape of an arbitrary-rank pooling operation from its window geometry.
This is the shape rule shared by Infer.nodeOutShape and the reference semantics: both call
planPool on the same configuration, so the evaluator's pooled tensor has exactly this shape.
Instances For
Infer the output shape of an arbitrary-rank pooling operation.
Instances For
Infer the output shape for the full parameterized convolution configuration.
Instances For
Infer dense, unit-dilation convolution output geometry for an arbitrary spatial rank.
This is the ordinary convolution specialization of inferConvConfigOutShape; keeping one checker
prevents the default and parameterized APIs from assigning different shapes to the same operation.
Instances For
Check eval-mode BatchNorm metadata against an arbitrary channel axis.