Soundness #
Tape-style (SSA/DAG) reverse-mode soundness for the proved-correct layer.
We model a dynamic graph as a sequence of nodes that may reference any previously computed values (so sharing/fan-out is allowed). For each node we assume a local JVP/VJP adjointness law, then prove the global reverse-mode accumulation algorithm is sound.
This is a proof-only layer; the runtime engine in NN.Runtime.Autograd.Engine is an
executable implementation of the same idea.
PyTorch correspondence / citations #
- This file is the proof analogue of PyTorch’s dynamic autograd engine building a tape of nodes during the forward pass and running a reverse pass that accumulates gradients at shared inputs. https://pytorch.org/docs/stable/autograd.html
References (background):
- Reverse-mode AD as backpropagation on a computation graph is standard; see e.g. Baydin et al. (JMLR 2018) for an overview and terminology (JVP/VJP, duality, etc.).
Dot product over contexts: sum of per-entry tensor dot products.
Informally: dotList xs ys is the “context inner product” used to state global adjointness for
tape evaluation and backprop.
Instances For
At ℝ the context dot product agrees with the backend-generic one in Algebra, entry by entry
through dot_eq_tensorAlgebra_dot.
A node with local JVP/VJP and an adjointness proof against the tensor dot product.
- forward : TorchLean.TensorPack ℝ Γ → TorchLean.Tensor ℝ τ
The node's forward pass, reading the whole context and producing one output tensor.
- jvp : TorchLean.TensorPack ℝ Γ → TorchLean.TensorPack ℝ Γ → TorchLean.Tensor ℝ τ
Forward-mode derivative: a basepoint and a tangent context give an output tangent.
- vjp : TorchLean.TensorPack ℝ Γ → TorchLean.Tensor ℝ τ → TorchLean.TensorPack ℝ Γ
Reverse-mode derivative: a basepoint and an output cotangent give a context cotangent.
- correct (x dx : TorchLean.TensorPack ℝ Γ) (δ : TorchLean.Tensor ℝ τ) : Spec.dot (self.jvp x dx) δ = TensorPack.dotList dx (self.vjp x δ)
- validate : TorchLean.TensorPack ℝ Γ → Except String Unit
Runtime precondition metadata, preserved by the algebraic bridge; pure semantics ignore it.
- prepare? : Option { prepare : Algebra.TensorLookup ℝ Γ → Algebra.PreparedNode ℝ Γ τ // ∀ (ctx : TorchLean.TensorPack ℝ Γ), (prepare (Algebra.TensorLookup.ofPack ctx)).toPreparedPrograms = { value := fun (x : Unit) => self.forward ctx, vjp := self.vjp ctx, validate := fun (x : Unit) => self.validate ctx } }
Certified local preparation, retained by both directions of the algebraic bridge.
Instances For
A tape/SSA graph: nodes are appended in topological order and may reference any previous value.
- nil {Γ : List Spec.Shape} : Graph Γ []
- snoc {Γ ss : List Spec.Shape} {τ : Spec.Shape} : Graph Γ ss → Node (Γ ++ ss) τ → Graph Γ (ss ++ [τ])
Instances For
Evaluate a tape/graph, returning the full context (inputs ++ intermediates).
Instances For
Evaluate the JVP (“forward-mode tangent”) of a graph, producing tangents for all values in the
extended context Γ ++ ss.
Instances For
Reverse-mode backpropagation on a tape/graph, returning gradients for the inputs Γ.
This is the proof model of what PyTorch calls “running backward” starting from an output seed cotangent and accumulating gradients at shared parents.
Instances For
Embed an analytic node as an algebraic node over ℝ with a trivial environment.
Instances For
Embed an analytic graph as an algebraic graph over ℝ with a trivial environment.
Instances For
Embedding preserves evaluation.
Embedding preserves the JVP.
Embedding preserves the reverse pass.
Global tape soundness: if each node satisfies a local JVP/VJP adjointness law, then the global
reverse-mode accumulation algorithm (backpropCtx) is correct.
Informally: for any input perturbation dx and any output seed cotangent seed,
⟪JVP(g, x, dx), seed⟫ = ⟪dx, backprop(g, x, seed)⟫.
This is the formal analogue of PyTorch’s guarantee that backward() computes vector–Jacobian
products and accumulates them through a dynamic DAG/tape. It is the ℝ, Δ := Unit instance of
Algebra.Graph.backprop_correct.