Backend Operation Interface #
Ops supplies the tensor primitives for models shared by eager and typed graph execution.
Ref and DataRef select the reference types of the current backend.
Tensor operations shared by eager and typed graph execution.
A model is polymorphic over this class. Eager instances execute and record a tape; typed graph instances build reusable graph data. Each instance must preserve the corresponding operator's forward and VJP semantics.
- Ref : Spec.Shape → Type
A differentiable tensor handle, indexed by its shape.
Backend representation of non-differentiable tensor data.
- dataConst {β : Type} [TorchLean.Storage β] {s : Spec.Shape} (x : TorchLean.Tensor β s) : DataRef m α β s
Lift fixed non-differentiable data into the backend representation.
- mapData {β γ : Type} [TorchLean.Storage β] [TorchLean.Storage γ] {s₁ s₂ : Spec.Shape} (f : TorchLean.Tensor β s₁ → TorchLean.Tensor γ s₂) (x : DataRef m α β s₁) : DataRef m α γ s₂
Apply a pure transformation to non-differentiable data.
- updateBuffers? : Option ({ss : List Spec.Shape} → {s : Spec.Shape} → RefList (Ref m α) ss → Ref m α s → (TorchLean.TensorPack α ss → TorchLean.Tensor α s → IO (TorchLean.TensorPack α ss)) → m Unit)
Observe a stateful layer's actual forward input and update its persistent buffers.
Pure interpreters may omit this hook. Runtime interpreters retain the recorded state values for differentiation and write updated values only to their persistent, non-trainable storage.
Record a fixed tensor value.
- observe : Ref m α Spec.Shape.scalar → m α
Inspect a scalar for eager control flow. The comparison is not differentiated; the tape records only the selected branch. Static graph builders reject this dynamic observation.
Add tensors elementwise.
Subtract tensors elementwise.
Multiply tensors elementwise.
Divide tensors elementwise, recording the quotient-rule VJP at nonzero denominators.
Negate each element directly, preserving the scalar's signed-zero convention.
Multiply every element by a scalar.
Take the elementwise absolute value.
Compute
sqrt(max(x, 0))elementwise. The selected JVP and VJP are zero forx ≤ 0; at positive inputs they use1 / (2 * sqrt(x)).Clamp every element between the lower and upper bounds. Input gradients pass through the open interval and are zero at both endpoints and outside it. The bounds are fixed scalar settings.
Take the elementwise maximum.
Take the elementwise minimum.
Repeat values along axes allowed by the broadcasting witness.
Change the shape while preserving scalar count and row-major order.
- swapAdjacentAtDepth {s : Spec.Shape} (depth : ℕ) (x : Ref m α s) : m (Ref m α (s.swapAdjacentAtDepth depth))
Swap the two adjacent axes starting at
depth. - reduceSum {s : Spec.Shape} (axis : ℕ) [Spec.Shape.HasNonemptyAxis axis s] [s.WellFormed] (x : Ref m α s) : m (Ref m α (TorchLean.Tensor.shapeAfterSum s axis))
Sum along
axisand remove it from the result shape. - reduceMean {s : Spec.Shape} (axis : ℕ) [Spec.Shape.HasNonemptyAxis axis s] [s.WellFormed] : Ref m α s → m (Ref m α (TorchLean.Tensor.shapeAfterSum s axis))
Average along
axisand remove it from the result shape. - select {s : Spec.Shape} (axis : ℕ) [Spec.Shape.AxisInBounds axis s] : Ref m α s → Fin (s.axisSize axis) → m (Ref m α (s.eraseAxis axis))
Select one position along
axis, removing that axis from the result. - indexSelect {s : Spec.Shape} (axis count : ℕ) [Spec.Shape.AxisInBounds axis s] : Ref m α s → DataRef m α (Fin (s.axisSize axis)) [count] → m (Ref m α (s.replaceAxis axis count))
Gather positions along
axisin the order given by the indices. - scatterAdd {s : Spec.Shape} (axis count : ℕ) [Spec.Shape.AxisInBounds axis s] : Ref m α s → Ref m α (s.replaceAxis axis count) → DataRef m α (Fin (s.axisSize axis)) [count] → m (Ref m α s)
Add source slices into the base at the selected positions along
axis. - matmul {batchA batchB batch : Spec.Shape} {mDim nDim pDim : ℕ} [batchA.BroadcastTo batch] [batchB.BroadcastTo batch] (a : Ref m α (batchA.concat [mDim, nDim])) (b : Ref m α (batchB.concat [nDim, pDim])) (scale : Option α := none) : m (Ref m α (batch.concat [mDim, pDim]))
Multiply matrices after broadcasting their batch prefixes to a common shape. A fixed
scalestays inside the contraction, including its local derivatives. - softmaxMatmul {batch : Spec.Shape} {rows keys width : ℕ} : Ref m α (batch.concat [rows, keys]) → Ref m α (batch.concat [keys, width]) → Ref m α (batch.concat [rows, keys]) → (mask : optParam (Option (TorchLean.Tensor Bool [rows, keys])) none) → m (Ref m α (batch.concat [rows, width]))
Normalize score rows, apply a differentiable multiplier, and mix value rows. The pullback retains the value contraction through normalization instead of requiring its intermediate cotangent to fit the scalar format. The optional mask excludes keys exactly.
- concat {nDim mDim : ℕ} {s : Spec.Shape} (a : Ref m α (s.prependDim nDim)) (b : Ref m α (s.prependDim mDim)) : m (Ref m α (s.prependDim (nDim + mDim)))
Concatenate tensors along their leading axis.
- slice {nDim : ℕ} {s : Spec.Shape} (start len : ℕ) (h : start + len ≤ nDim) (x : Ref m α (s.prependDim nDim)) : m (Ref m α (s.prependDim len))
Take
lenentries of the leading axis, starting atstart. - maxPool {d C : ℕ} {inSpatial kernel stride padding : TorchLean.Tensor ℕ [d]} (x : Ref m α (Spec.Shape.ofList (C :: inSpatial.to (List ℕ)))) : m (Ref m α (Spec.Shape.ofList (C :: (Spec.poolOutSpatialPad inSpatial kernel stride padding).to (List ℕ))))
Apply spatial max pooling to one channels-first sample.
- avgPool {d C : ℕ} {inSpatial kernel stride padding : TorchLean.Tensor ℕ [d]} (x : Ref m α (Spec.Shape.ofList (C :: inSpatial.to (List ℕ)))) : m (Ref m α (Spec.Shape.ofList (C :: (Spec.poolOutSpatialPad inSpatial kernel stride padding).to (List ℕ))))
Apply spatial average pooling to one channels-first sample, counting padding as zeros.
- smoothMaxPool {d C : ℕ} {inSpatial kernel stride padding : TorchLean.Tensor ℕ [d]} [DecidableEq α] : Ref m α (Spec.Shape.ofList (C :: inSpatial.to (List ℕ))) → α → m (Ref m α (Spec.Shape.ofList (C :: (Spec.poolOutSpatialPad inSpatial kernel stride padding).to (List ℕ))))
Apply a smooth approximation to spatial max pooling, with sharpness
beta. Replace negative elements with zero.
Apply the logistic sigmoid elementwise.
Apply SiLU with its input-based value and VJP, retaining representable negative tails.
Apply the hyperbolic tangent elementwise.
Apply tanh-approximate GELU as one recorded operation.
The formula is
0.5 * x * (1 + tanh(√(2/π) * (x + 0.044715 * x^3))). A backend may evaluate it through several numerical primitives and temporary tensors without recording separate tape nodes for the terms. The value and VJP followActivation.geluSpecandActivation.geluDerivSpec.Apply softmax over the final tensor dimension.
Apply stable log-softmax over the final tensor dimension.
Separate one maximal exponential and normalize the remaining tail with
log1p. Arbitrary-axis operations move their selected axis to the final position before calling this primitive. Backward must preserve small complementary probabilities near one.Apply
log(1 + exp(x))elementwise.Take the elementwise exponential.
Take the elementwise sine of angles in radians. JVPs and VJPs multiply by
cos(x), evaluated at the original input, so differentiation preserves the derivative's sign across periods.Take the elementwise cosine of angles in radians, with derivative
-sin(x).Take the elementwise logarithm.
Take the elementwise reciprocal.
Keep the value and stop gradients through this reference.
One for the
klargest entries of every row along the last axis and zero for the others, with ties going to the lower index (Spec.MoE.topKMaskSpec); a row with NaN can keep a different number of entries. The mask is constant away from ties and no gradient flows through it; a router learns through the gates the mask selects.- safeLog {s : Spec.Shape} : Ref m α s → α → m (Ref m α s)
Apply
log(softplus(x) + epsilon)elementwise.The derivative is
sigmoid(x) / (softplus(x) + epsilon), withepsilonheld fixed. Over the reals, positiveepsilonkeeps the argument positive. Executable arithmetic needsepsilonto remain positive in its selected representation; this does not make nonfinite inputs finite. Sum every element into a scalar.
Flatten all axes into one, preserving row-major order.
- linear {inDim outDim : ℕ} (w : Ref m α [outDim, inDim]) (b : Ref m α [outDim]) (x : Ref m α [inDim]) : m (Ref m α [outDim])
Apply
weight * input + biasto one input vector. Average the squared elementwise difference between prediction and target.
- crossEntropy {s : Spec.Shape} (axis : ℕ) [Spec.Shape.AxisInBounds axis s] (logits target : Ref m α s) (mean : Bool := true) : m (Ref m α Spec.Shape.scalar)
Cross-entropy from logits and target weights along
axis. Both inputs receive gradients. The default mean divides by class slices, not target mass;mean := falsekeeps the sum. - distill {s : Spec.Shape} (axis : ℕ) [Spec.Shape.AxisInBounds axis s] (student teacher : Ref m α s) : m (Ref m α Spec.Shape.scalar)
Mean cross-entropy from teacher logits along
axis. Only the student receives gradients; callers detach the teacher to clear forward-mode metadata as well. - layerNorm {seqLen embedDim : ℕ} (h_seq_pos : seqLen > 0) (h_embed_pos : embedDim > 0) (x : Ref m α [seqLen, embedDim]) (gamma beta : Ref m α [embedDim]) (epsilon : α := TorchLean.normalizationEpsilon) : m (Ref m α [seqLen, embedDim])
Normalize each row over its embedding axis, then apply scale and bias.
The denominator is
sqrt(variance + epsilon). Forward and backward use the sameepsilon; gradients are taken with respect to the input, scale, and bias whileepsilonstays fixed. - batchNorm {channels : ℕ} {sSpatial : Spec.Shape} (hWellFormed : (sSpatial.prependDim channels).wellFormed) (x : Ref m α (sSpatial.prependDim channels)) (gamma beta : Ref m α [channels]) (epsilon : α := TorchLean.normalizationEpsilon) : m (Ref m α (sSpatial.prependDim channels))
Normalize each channel over its spatial axes, then apply scale and bias.
The denominator is
sqrt(variance + epsilon). Forward and backward use the sameepsilon; gradients are taken with respect to the input, scale, and bias whileepsilonstays fixed. - attention {n numHeads dModel headDim : ℕ} {batch : Option ℕ} (hBatch : batch.getD 1 ≠ 0) (h1 : n ≠ 0) : Ref m α [dModel, numHeads * headDim] → Ref m α [dModel, numHeads * headDim] → Ref m α [dModel, numHeads * headDim] → Ref m α [numHeads * headDim, dModel] → Ref m α (match batch with | none => [n, dModel] | some b => [b, n, dModel]) → Option (TorchLean.Tensor Bool [n, n]) → m (Ref m α (match batch with | none => [n, dModel] | some b => [b, n, dModel]))
Self-attention, optionally over a leading batch dimension.
batch := noneselects one sequence;some bselectsbindependent sequences with shared projections and mask. Batching preserves the per-sequence forward and VJP semantics. - conv {d inC outC : ℕ} {kernel stride padding inSpatial : TorchLean.Tensor ℕ [d]} (weight : Ref m α (Spec.Shape.ofList (outC :: inC :: kernel.to (List ℕ)))) (bias : Ref m α [outC]) (input : Ref m α (Spec.Shape.ofList (inC :: inSpatial.to (List ℕ)))) : m (Ref m α (Spec.Shape.ofList (outC :: (Spec.convOutSpatial inSpatial kernel stride padding).to (List ℕ))))
Apply spatial convolution to one channels-first sample.
- convTranspose {d inC outC : ℕ} {kernel stride padding inSpatial : TorchLean.Tensor ℕ [d]} (weight : Ref m α (Spec.Shape.ofList (inC :: outC :: kernel.to (List ℕ)))) (bias : Ref m α [outC]) (input : Ref m α (Spec.Shape.ofList (inC :: inSpatial.to (List ℕ)))) : m (Ref m α (Spec.Shape.ofList (outC :: (Spec.convTransposeOutSpatial inSpatial kernel stride padding).to (List ℕ))))
Apply spatial transpose convolution to one channels-first sample.
Draw a uniform tensor from the seed and the backend's node or call index.
No
IOrandomness is used, so a fixed graph can replay the draw.Draw a seeded mask with the scalar reference as its keep probability.
- rfft1dNative? : Option ({batch n : ℕ} → Ref m α [batch, n] → m (Option (Ref m α [batch, n / 2 + 1, 2])))
Optional native packed real transform. Returning
noneleaves the operation to the generic differentiable implementation; a backend must not record any nodes before declining the call. The output stores real and imaginary components in its final axis. - irfft1dNative? : Option ({batch n : ℕ} → Ref m α [batch, n / 2 + 1, 2] → m (Option (Ref m α [batch, n])))
Optional normalized inverse of the packed real transform, with explicit output length.
- selectiveScanDiagNative? : Option ({seqLen state : ℕ} → Ref m α [state] → Ref m α [state] → Ref m α [seqLen, state] → Ref m α [state] → m (Option (Ref m α [seqLen, state])))
Optional diagonal recurrence with coefficients shared across time and all four VJPs.
- selectiveScanDiagVarNative? : Option ({seqLen state : ℕ} → Ref m α [seqLen, state] → Ref m α [seqLen, state] → Ref m α [seqLen, state] → Ref m α [state] → m (Option (Ref m α [seqLen, state])))
Optional diagonal recurrence with token-dependent coefficients and all four VJPs.
Instances
Differentiable reference type of the current backend.
Instances For
Backend representation of a non-differentiable tensor.