TorchLean API

NN.Proofs.RuntimeApprox.Scale.ScaleApprox

ScaleApprox #

Scale-aware approximation helpers.

This module adds an optional layer that tracks a per-tensor "scale bound" (a nonnegative bound on linfNorm) alongside the existing eps error bounds.

It is designed to be used to derive readable abs+rel tolerances from existing eps-style proofs: given an error budget eps and a scale bound B, we can form an ApproxTol whose rel component is computed from (eps / B) (with safe handling of B = 0).

Nothing here changes existing forward/backward frameworks; it only provides new predicates and lemmas you can opt into.

PyTorch correspondence / citations #

This is the proof-oriented analogue of reasoning with a magnitude/scale estimate (e.g. ‖x‖∞ ≤ B) to turn an absolute error budget into an rtol-style relative tolerance. https://pytorch.org/docs/stable/generated/torch.allclose.html

Nonnegative scale bounds aligned with a context shape list.

Instances For
    def Proofs.RuntimeApprox.BList.cast {ss₁ ss₂ : List Spec.Shape} (h : ss₁ = ss₂) (xs : BList ss₁) :
    BList ss₂

    Transport a BList along an equality of the underlying shape lists.

    Instances For
      @[simp]
      theorem Proofs.RuntimeApprox.BList.cast_rfl {ss : List Spec.Shape} (xs : BList ss) :
      cast xs = xs

      Transporting along rfl is the identity.

      Append one additional scale bound at the end of a BList.

      Instances For

        Split a BList (ss ++ [τ]) into its prefix and the last bound.

        Instances For
          @[simp]
          theorem Proofs.RuntimeApprox.BList.unsnoc_snoc {ss : List Spec.Shape} {τ : Spec.Shape} (xs : BList ss) (e : NNReal) :
          (xs.snoc e).unsnoc = (xs, e)

          unsnoc undoes snoc.

          Graph evaluation appends one bound per node, so the pair snoc/unsnoc is how a scale list follows a growing context. This lemma is what keeps the induction on graph length from having to reason about list append at all.

          Get the ith scale bound from a BList (using the Fin ss.length index).

          Instances For
            def Proofs.RuntimeApprox.scaleWith {α : Type} [TorchLean.Storage α] {s : Spec.Shape} (toSpec : αSpec.SpecScalar) (norm : {s : Spec.Shape} → Spec.SpecTensor sSpec.SpecScalar) (spec : Spec.SpecTensor s) (runtime : TorchLean.Tensor α s) (B : NNReal) :

            A scale bound says both spec and runtime (mapped to spec) norms are bounded by B.

            Instances For
              def Proofs.RuntimeApprox.scaleTensor {α : Type} [TorchLean.Storage α] {s : Spec.Shape} (toSpec : αSpec.SpecScalar) (spec : Spec.SpecTensor s) (runtime : TorchLean.Tensor α s) (B : NNReal) :

              Default scale predicate on tensors (uses linfNorm).

              Instances For

                Context-level scale predicate aligned with a BList.

                Instances For
                  theorem Proofs.RuntimeApprox.scaleCtx_cast {α : Type} [TorchLean.Storage α] {toSpec : αSpec.SpecScalar} {ss₁ ss₂ : List Spec.Shape} (h : ss₁ = ss₂) {xS : TorchLean.TensorPack Spec.SpecScalar ss₁} {xR : TorchLean.TensorPack α ss₁} {bs : BList ss₁} :
                  scaleCtx toSpec xS xR bsscaleCtx toSpec (TorchLean.TensorPack.cast h xS) (TorchLean.TensorPack.cast h xR) (BList.cast h bs)

                  The context scale predicate survives transporting all three arguments along the same equality.

                  theorem Proofs.RuntimeApprox.scaleCtx_snoc {α : Type} [TorchLean.Storage α] {toSpec : αSpec.SpecScalar} {ss : List Spec.Shape} {τ : Spec.Shape} {xS : TorchLean.TensorPack Spec.SpecScalar ss} {xR : TorchLean.TensorPack α ss} {bs : BList ss} (hx : scaleCtx toSpec xS xR bs) {yS : Spec.SpecTensor τ} {yR : TorchLean.Tensor α τ} {b : NNReal} (hy : scaleTensor toSpec yS yR b) :
                  scaleCtx toSpec (xS.snoc yS) (xR.snoc yR) (bs.snoc b)

                  Appending a tensor with a known scale bound extends the context predicate.

                  This is the step used every time a node's output is pushed onto the context: the existing bounds are untouched and the new one only has to hold for the new entry.

                  theorem Proofs.RuntimeApprox.scaleCtx_unsnoc {α : Type} [TorchLean.Storage α] {toSpec : αSpec.SpecScalar} {ss : List Spec.Shape} {τ : Spec.Shape} {xS : TorchLean.TensorPack Spec.SpecScalar (ss ++ [τ])} {xR : TorchLean.TensorPack α (ss ++ [τ])} {bs : BList (ss ++ [τ])} :
                  scaleCtx toSpec xS xR bsscaleCtx toSpec xS.unsnoc.1 xR.unsnoc.1 bs.unsnoc.1 scaleTensor toSpec xS.unsnoc.2 xR.unsnoc.2 bs.unsnoc.2

                  Conversely, a predicate on an extended context splits into the prefix part and the last entry.

                  theorem Proofs.RuntimeApprox.scaleCtx_get {α : Type} [TorchLean.Storage α] {toSpec : αSpec.SpecScalar} {Γ : List Spec.Shape} {xS : TorchLean.TensorPack Spec.SpecScalar Γ} {xR : TorchLean.TensorPack α Γ} {bs : BList Γ} (h : scaleCtx toSpec xS xR bs) (i : Fin Γ.length) :
                  scaleTensor toSpec (xS.get i) (xR.get i) (bs.get i)

                  Every individual entry of a context that satisfies scaleCtx satisfies its own scale bound.

                  Stated for an arbitrary index rather than only for the head, because a node reads its inputs from anywhere in the context.

                  noncomputable def Proofs.RuntimeApprox.tolFromEpsScale (eps : ) (B : NNReal) :

                  A derived tolerance from an absolute error eps and a scale bound B.

                  We always keep the absolute component (abs = eps) for safety. The relative component is computed as eps / B (with a B = 0 guard) and then clamped to be nonnegative via toNNReal inside ApproxTol.ofReal.

                  Instances For

                    tolFromEpsScale is at least as permissive as the absolute-only tolerance in every field.

                    That is the whole reason the absolute component is kept rather than traded for the relative one: the derived tolerance can then be reached from an absolute bound by monotonicity alone, with no case analysis on whether B is zero.

                    theorem Proofs.RuntimeApprox.approxTensorWithTol_from_scale {α : Type} [TorchLean.Storage α] {s : Spec.Shape} {toSpec : αSpec.SpecScalar} {spec : Spec.SpecTensor s} {runtime : TorchLean.Tensor α s} (eps : ) (B : NNReal) (h : approxTensor toSpec spec runtime eps) :
                    approxTensorWithTol toSpec spec runtime (tolFromEpsScale eps B)

                    An absolute tensor bound upgrades to the abs-plus-rel tolerance derived from a scale bound.

                    theorem Proofs.RuntimeApprox.approxCtx_get_tolFromEpsScale {α : Type} [TorchLean.Storage α] {toSpec : αSpec.SpecScalar} {Γ : List Spec.Shape} {xS : TorchLean.TensorPack Spec.SpecScalar Γ} {xR : TorchLean.TensorPack α Γ} {eps : EList Γ} {bs : BList Γ} ( : approxCtx toSpec xS xR eps) (_hB : scaleCtx toSpec xS xR bs) (i : Fin Γ.length) :
                    approxTensorWithTol toSpec (xS.get i) (xR.get i) (tolFromEpsScale (eps.get i) (bs.get i))

                    Per-entry form of the upgrade: each context slot gets the tolerance derived from its own eps and its own scale bound.

                    The scale hypothesis is currently unused in the proof, since the derived tolerance is reached purely by weakening. It stays in the signature because it is what makes the resulting relative component meaningful, and dropping it would let callers form tolerances against a scale nothing satisfies.