BackwardApprox #
Reverse-mode (backward) runtime→spec approximation framework.
This is the backward analogue of NN/Proofs/RuntimeApprox/Graph/ForwardApprox.lean.
It models a tape/SSA-style DAG where each node provides:
- a forward map (spec + runtime) with an explicit forward error bound (as in
FwdNode); - a local VJP (reverse-mode) map (spec + runtime) with an explicit VJP error bound.
The global theorem RevGraph.backprop_approx composes these local bounds over the whole graph,
analogously to FwdGraph.eval_approx.
Note: reverse-mode accumulation uses context-wise addition; the corresponding bound/soundness
for accumulation is an explicit parameter to the theorem (addBound, addSound).
What you get #
RevGraph.eval_approx: a forward approximation theorem for the runtime/spec node contexts.RevGraph.backprop_approx: an end-to-end approximation theorem for reverse-mode accumulation (VJP-based backprop on the whole graph).
Reading guide #
RevNode/RevGraph: nodes carry both forward and VJP approximation data.RevGraph.eval_*: reuse the forward theory by forgetting VJP data.RevGraph.backprop*: executable reverse-mode accumulation + its explicit bound propagation.RevGraph.backprop_approx: composes node-local VJP bounds and accumulation bounds over the whole graph (induction over the snoc-list).
PyTorch correspondence / citations #
This mirrors the structure of reverse-mode AD in PyTorch Autograd: a forward pass produces intermediate values, and a backward pass propagates cotangents/gradients in reverse topological order while accumulating contributions at shared nodes. https://pytorch.org/docs/stable/autograd.html
Componentwise addition of error lists (used when accumulating cotangent/gradient bounds).
Instances For
A node with both forward and VJP approximation data.
- forwardRuntime : TList α Γ → Spec.Tensor α τ
- bound : EList Γ → TList α Γ → Spec.SpecScalar
- sound (xS : TList Spec.SpecScalar Γ) (xR : TList α Γ) (eps : EList Γ) : approxCtx toSpec xS xR eps → approxT toSpec (self.forwardSpec xS) (self.forwardRuntime xR) (self.bound eps xR)
- vjpSpec : TList Spec.SpecScalar Γ → Spec.SpecTensor τ → TList Spec.SpecScalar Γ
Spec-level VJP: maps a context and an output cotangent into a context cotangent.
- vjpRuntime : TList α Γ → Spec.Tensor α τ → TList α Γ
Runtime VJP: same shape-level function on the runtime side.
- vjpBound : EList Γ → TList α Γ → Spec.SpecScalar → Spec.Tensor α τ → EList Γ
Explicit bound transformer for VJP: pushes bounds backward through this node.
- vjpSound (ctxS : TList Spec.SpecScalar Γ) (ctxR : TList α Γ) (epsCtx : EList Γ) (δS : Spec.SpecTensor τ) (δR : Spec.Tensor α τ) (epsδ : Spec.SpecScalar) : approxCtx toSpec ctxS ctxR epsCtx → approxT toSpec δS δR epsδ → approxCtx toSpec (self.vjpSpec ctxS δS) (self.vjpRuntime ctxR δR) (self.vjpBound epsCtx ctxR epsδ δR)
Soundness of the VJP bound: if context + output cotangent are approximated, so is the VJP.
Instances For
Tape/SSA DAG with reverse-mode metadata (nodes appended in topological order).
Compared to FwdGraph, each node additionally carries a local VJP rule (RevNode.vjp*) plus an
explicit error transformer vjpBound and its soundness lemma vjpSound.
- nil {α : Type} {toSpec : α → Spec.SpecScalar} {Γ : List Spec.Shape} : RevGraph toSpec Γ []
- snoc {α : Type} {toSpec : α → Spec.SpecScalar} {Γ ss : List Spec.Shape} {τ : Spec.Shape} : RevGraph toSpec Γ ss → RevNode toSpec (Γ ++ ss) τ → RevGraph toSpec Γ (ss ++ [τ])
Instances For
Forget the VJP metadata of a RevGraph, yielding a FwdGraph with the same node ordering.
This lets us reuse the forward approximation theorem (FwdGraph.eval_approx) for free.
Instances For
Spec-level evaluation of a RevGraph (delegates to toFwdGraph).
Instances For
Runtime-level evaluation of a RevGraph (delegates to toFwdGraph).
Instances For
Forward bound propagation for a RevGraph (delegates to toFwdGraph).
Instances For
Forward approximation theorem for RevGraph (just FwdGraph.eval_approx via toFwdGraph).
Spec-level reverse-mode evaluation.
Informally: run the forward pass to get node contexts, then traverse nodes in reverse topological order, applying each node’s VJP and accumulating the resulting context-cotangent into the running seed.
Instances For
Runtime-level reverse-mode accumulation.
This mirrors backpropSpec, but uses runtime tensors and relies on an Add α instance to
accumulate contributions at shared nodes.
Instances For
Backward error propagation for backprop*.
This is parameterized by:
addBound: how to compute the (per-entry) error list for context-wise addition.
addBound may depend on the runtime addends, to account for rounding models.
Instances For
End-to-end reverse-mode approximation theorem for RevGraph.backprop*.
Informally:
assume (1) the runtime inputs xR approximate the spec inputs xS with bounds epsIn, and
(2) the runtime seed cotangents seedR approximate the spec seeds seedS with bounds epsSeed.
Then the whole backprop result backpropRuntime g xR seedR approximates the spec backprop result
backpropSpec g xS seedS, with an explicit bound computed by backpropBounds.
The only "extra" ingredient beyond per-node VJP approximation is how we accumulate contributions:
addBound describes how addition affects error bounds, and addSound is the theorem justifying it
(e.g. for exact reals it is trivial; for rounding models it carries the rounding-error analysis).